module Vgrep.Widget.Results.Internal (
Results (..)
, currentFileName
, currentLineNumber
, currentFileResults
, feed
, showPrev, showNext
, hidePrev, hideNext
, moveUp, moveDown
, resize
, DisplayLine(..)
, toLines
, displayLineNumber
) where
import Control.Applicative
import Control.Lens.Compat (Getter, pre, to, view, _Just)
import Data.Foldable
import Data.Function
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as Map
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.Ansi (AnsiFormatted)
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 . view lineReference) fileResults
header = pure . FileHeader . view file
selected = pure . SelectedLine . view lineReference
pointsToSameFile = (==) `on` view file
displayLineNumber :: DisplayLine -> Maybe Int
displayLineNumber = \case
FileHeader _ -> Nothing
Line (LineReference n _) -> n
SelectedLine (LineReference n _) -> n
currentFileName :: Getter Results (Maybe Text)
currentFileName =
pre (to current . _Just . file . fileName)
currentLineNumber :: Getter Results (Maybe Int)
currentLineNumber =
pre (to current . _Just . lineReference . lineNumber . _Just)
current :: Results -> Maybe FileLineReference
current = \case
Results _ _ c _ _ -> Just c
EmptyResults -> Nothing
currentFileResults :: Getter Results (IntMap AnsiFormatted)
currentFileResults =
to (Map.fromList . lineReferencesInCurrentFile)
where
lineReferencesInCurrentFile = do
let sameFileAs = (==) `on` view file
inCurrentFile <- sameFileAs . fromJust . current
results <- map (view lineReference) . filter inCurrentFile . bufferToList
pure [ (ln, txt) | LineReference (Just ln) txt <- results ]
bufferToList :: Results -> [FileLineReference]
bufferToList = \case
EmptyResults -> []
Results as bs c ds es -> toList (as <> bs <> pure c <> ds <> es)