1
1
mirror of https://github.com/github/semantic.git synced 2024-12-26 00:12:29 +03:00
semantic/src/Source.hs

70 lines
2.6 KiB
Haskell
Raw Normal View History

2015-12-30 01:34:52 +03:00
2015-12-24 06:38:02 +03:00
module Source where
import Range
2015-12-24 06:48:31 +03:00
import qualified Data.Vector as Vector
2015-12-30 01:34:52 +03:00
import qualified Data.Text as T
2016-02-10 22:32:26 +03:00
data SourceBlob = SourceBlob { source :: Source Char, oid :: String, path :: FilePath }
2016-01-27 00:25:40 +03:00
2016-01-13 23:50:52 +03:00
-- | The contents of a source file, backed by a vector for efficient slicing.
newtype Source a = Source { getVector :: Vector.Vector a }
2015-12-29 18:21:45 +03:00
deriving (Eq, Show, Functor, Foldable, Traversable)
2016-01-13 23:50:52 +03:00
-- | Return a Source from a list of items.
2015-12-24 07:37:51 +03:00
fromList :: [a] -> Source a
fromList = Source . Vector.fromList
2016-01-13 23:50:52 +03:00
-- | Return a Source of Chars from a Text.
2015-12-30 01:34:52 +03:00
fromText :: T.Text -> Source Char
fromText = Source . Vector.fromList . T.unpack
2016-01-13 23:50:52 +03:00
-- | Return a list of items with the contents of the Source.
2015-12-24 07:26:37 +03:00
toList :: Source a -> [a]
toList = Vector.toList . getVector
2016-01-13 23:50:52 +03:00
-- | Return a Source that contains a slice of the given Source.
2015-12-24 07:25:00 +03:00
slice :: Range -> Source a -> Source a
2016-01-12 19:56:36 +03:00
slice range = Source . Vector.slice (start range) (rangeLength range) . getVector
2016-01-13 23:50:52 +03:00
-- | Return a String with the contents of the Source.
toString :: Source Char -> String
2015-12-24 07:26:37 +03:00
toString = toList
2016-01-13 23:50:52 +03:00
-- | Return the item at the given index.
at :: Source a -> Int -> a
2015-12-24 07:29:27 +03:00
at = (Vector.!) . getVector
2016-01-13 23:50:52 +03:00
-- | Test whether the source is empty.
null :: Source a -> Bool
2015-12-24 07:28:13 +03:00
null = Vector.null . getVector
2015-12-24 07:05:01 +03:00
2016-01-13 23:50:52 +03:00
-- | Prepend an item.
2015-12-24 07:06:49 +03:00
cons :: a -> Source a -> Source a
cons a = Source . Vector.cons a . getVector
2016-01-13 23:50:52 +03:00
-- | Remove the first item and return it with the rest of the source.
2015-12-24 07:05:01 +03:00
uncons :: Source a -> Maybe (a, Source a)
uncons (Source vector) = if Vector.null vector then Nothing else Just (Vector.head vector, Source $ Vector.tail vector)
2015-12-24 07:16:09 +03:00
2016-01-13 23:50:52 +03:00
-- | Split the source into the longest prefix of elements that do not satisfy the predicate and the rest without copying.
2015-12-24 07:16:09 +03:00
break :: (a -> Bool) -> Source a -> (Source a, Source a)
2015-12-24 07:23:16 +03:00
break predicate (Source vector) = let (start, remainder) = Vector.break predicate vector in (Source start, Source remainder)
2015-12-24 07:41:08 +03:00
2016-01-13 23:50:52 +03:00
-- | Concatenate two sources.
2015-12-24 07:41:08 +03:00
(++) :: Source a -> Source a -> Source a
(++) (Source a) = Source . (a Vector.++) . getVector
2016-01-14 00:20:29 +03:00
-- | Split the contents of the source after newlines.
actualLines :: Source Char -> [Source Char]
2015-12-24 08:23:36 +03:00
actualLines source | Source.null source = [ source ]
actualLines source = case Source.break (== '\n') source of
(l, lines') -> case uncons lines' of
Nothing -> [ l ]
Just (_, lines') -> (l Source.++ fromList "\n") : actualLines lines'
-- | Compute the line ranges within a given range of a string.
actualLineRanges :: Range -> Source Char -> [Range]
actualLineRanges range = drop 1 . scanl toRange (Range (start range) (start range)) . actualLines . slice range
where toRange previous string = Range (end previous) $ end previous + length string