module Vgrep.Widget.Results.Internal (
Results (..)
, currentFileName
, currentLineNumber
, currentFileResultLineNumbers
, feed
, showPrev, showNext
, hidePrev, hideNext
, moveUp, moveDown
, resize
, DisplayLine(..)
, toLines
, lineNumber
) where
import Control.Applicative
import Control.Lens (Getter, pre, to, _Just)
import Data.Foldable
import Data.Function
import Data.List (groupBy)
import Data.Maybe
import Data.Monoid
import Data.Sequence
( Seq
, ViewL (..)
, ViewR (..)
, viewl
, viewr
, (<|)
, (|>)
)
import qualified Data.Sequence as S
import Data.Text (Text)
import Prelude hiding (reverse)
import Vgrep.Results
data Results
= EmptyResults
| Results
!(Seq FileLineReference)
!(Seq FileLineReference)
!FileLineReference
!(Seq FileLineReference)
!(Seq FileLineReference)
deriving (Eq, Show)
feed :: FileLineReference -> Results -> Results
feed l = \case
EmptyResults -> Results empty empty l empty empty
Results as bs c ds es -> Results as bs c ds (es |> l)
reverse :: Results -> Results
reverse = \case
Results as bs c ds es -> Results es ds c bs as
EmptyResults -> EmptyResults
showNext :: Results -> Maybe Results
showNext = \case
Results as bs c ds es -> do e :< es' <- Just (viewl es)
Just (Results as bs c (ds |> e) es')
EmptyResults -> Nothing
showPrev :: Results -> Maybe Results
showPrev = fmap reverse . showNext . reverse
hideNext :: Results -> Maybe Results
hideNext = \case
Results as bs c ds es -> do ds' :> d <- Just (viewr ds)
Just (Results as bs c ds' (d <| es))
EmptyResults -> Nothing
hidePrev :: Results -> Maybe Results
hidePrev = fmap reverse . hideNext . reverse
moveDown :: Results -> Maybe Results
moveDown = \case
Results as bs c ds es -> do d :< ds' <- Just (viewl ds)
Just (Results as (c <| bs) d ds' es)
EmptyResults -> Nothing
moveUp :: Results -> Maybe Results
moveUp = fmap reverse . moveDown . reverse
resize
:: Int
-> Results
-> Maybe Results
resize height buffer
| visibleHeight buffer < height 1 = Just (doResize buffer)
| visibleHeight buffer > height = Just (doResize buffer)
| otherwise = Nothing
where
doResize buf
| visibleHeight buf < height 1
= maybe buf doResize (showNext buf <|> showPrev buf)
| visibleHeight buf > height
= maybe buf doResize (hidePrev buf <|> hideNext buf)
| otherwise
= buf
visibleHeight :: Results -> Int
visibleHeight = length . toLines
data DisplayLine = FileHeader File
| Line LineReference
| SelectedLine LineReference
deriving (Eq)
toLines :: Results -> [DisplayLine]
toLines EmptyResults = []
toLines (Results _ bs c ds _) = linesBefore <> selected c <> linesAfter
where
linesBefore = case viewl bs of
b :< _ | b `pointsToSameFile` c -> go (S.reverse bs)
_otherwise -> go (S.reverse bs) <> header c
linesAfter = case viewl ds of
d :< _ | c `pointsToSameFile` d -> drop 1 (go ds)
_otherwise -> go ds
go refs = do
fileResults <- groupBy pointsToSameFile (toList refs)
header (head fileResults) <> fmap (Line . getLineReference) fileResults
header = pure . FileHeader . getFile
selected = pure . SelectedLine . getLineReference
pointsToSameFile = (==) `on` getFile
lineNumber :: DisplayLine -> Maybe Int
lineNumber = \case
FileHeader _ -> Nothing
Line (LineReference n _) -> n
SelectedLine (LineReference n _) -> n
currentFileName :: Getter Results (Maybe Text)
currentFileName =
pre (to current . _Just . to getFile . to getFileName)
currentLineNumber :: Getter Results (Maybe Int)
currentLineNumber =
pre (to current . _Just . to getLineReference . to getLineNumber . _Just)
current :: Results -> Maybe FileLineReference
current = \case
Results _ _ c _ _ -> Just c
EmptyResults -> Nothing
currentFileResultLineNumbers :: Getter Results [Int]
currentFileResultLineNumbers =
to (mapMaybe getLineNumber . currentFile)
where
currentFile = do
let sameFileAs = (==) `on` getFile
inCurrentFile <- sameFileAs . fromJust . current
map getLineReference . filter inCurrentFile . bufferToList
bufferToList :: Results -> [FileLineReference]
bufferToList = \case
EmptyResults -> []
Results as bs c ds es -> toList (as <> bs <> pure c <> ds <> es)