module UseCounts.Output
  ( usageOutput
  ) where

import           Data.List
import           Data.Map.Append.Strict (AppendMap(..))
import qualified Data.Map.Strict as M
import           Data.Ord (Down(..))

import           GHC.Api (Name, pprDefinedAt)
import           GHC.Output
import           UseCounts.ProcessHie (UsageCounter, UsageCount(..))

limit :: Int
limit :: Int
limit = Int
15

usageOutput :: UsageCounter -> SDoc
usageOutput :: UsageCounter -> SDoc
usageOutput (AppendMap Map Name UsageCount
usageCounter) =
  if forall (t :: * -> *) a. Foldable t => t a -> Int
length [SDoc]
uses forall a. Ord a => a -> a -> Bool
< Int
limit
     then [SDoc] -> SDoc
vcat [SDoc]
uses
     else [SDoc] -> SDoc
vcat [ String -> SDoc
text forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show Int
limit forall a. [a] -> [a] -> [a]
++ String
" Least used definitions:"
               , [SDoc] -> SDoc
vcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> [a] -> [a]
take Int
limit forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
reverse [SDoc]
uses
               , String -> SDoc
text String
""
               , String -> SDoc
text forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show Int
limit forall a. [a] -> [a] -> [a]
++ String
" Most used definitions:"
               , [SDoc] -> SDoc
vcat forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
take Int
limit [SDoc]
uses
               ]
  where
    uses :: [SDoc]
uses = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Name -> UsageCount -> SDoc
usageLine)
         forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (forall a. a -> Down a
Down forall b c a. (b -> c) -> (a -> b) -> a -> c
. UsageCount -> Int
usages forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd)
         forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Map k a -> [(k, a)]
M.toList
         forall a b. (a -> b) -> a -> b
$ forall a k. (a -> Bool) -> Map k a -> Map k a
M.filter UsageCount -> Bool
locallyDefined Map Name UsageCount
usageCounter

usageLine :: Name -> UsageCount -> SDoc
usageLine :: Name -> UsageCount -> SDoc
usageLine Name
name UsageCount
usage
  = let numUses :: Int
numUses = UsageCount -> Int
usages UsageCount
usage
        u :: SDoc
u | Int
numUses forall a. Eq a => a -> a -> Bool
== Int
1 = String -> SDoc
text String
"use"
          | Bool
otherwise = String -> SDoc
text String
"uses"
        in  Name -> SDoc
nameOutput Name
name
        SDoc -> SDoc -> SDoc
$+$ Int -> SDoc -> SDoc
nest Int
2 (PprColour -> SDoc -> SDoc
coloured PprColour
colCyanFg (forall a. Integral a => a -> SDoc
intWithCommas Int
numUses) SDoc -> SDoc -> SDoc
<+> SDoc
u)

nameOutput :: Name -> SDoc
nameOutput :: Name -> SDoc
nameOutput Name
name = SDoc
nameDoc SDoc -> SDoc -> SDoc
<+> SDoc
locDoc where
  nameDoc :: SDoc
nameDoc = PprColour -> SDoc -> SDoc
coloured PprColour
colYellowFg forall a b. (a -> b) -> a -> b
$ forall a. Outputable a => a -> SDoc
ppr Name
name
  locDoc :: SDoc
locDoc = PprColour -> SDoc -> SDoc
coloured PprColour
colMagentaFg forall b c a. (b -> c) -> (a -> b) -> a -> c
. SDoc -> SDoc
parens forall a b. (a -> b) -> a -> b
$ Name -> SDoc
pprDefinedAt Name
name