module Ribosome.Menu.Nvim where

import Control.Lens (view)
import qualified Data.Map as Map (fromList)
import qualified Data.Text as Text (cons, snoc)

import Ribosome.Api.Window (redraw, setLine)
import Ribosome.Control.Monad.Ribo (MonadRibo, NvimE)
import Ribosome.Data.List (mapSelectors)
import Ribosome.Data.Scratch (Scratch(scratchWindow))
import Ribosome.Data.ScratchOptions (ScratchOptions)
import Ribosome.Data.Syntax (
  HiLink(..),
  Syntax(Syntax),
  SyntaxItem(..),
  syntaxMatch,
  )
import Ribosome.Log (logDebug)
import qualified Ribosome.Menu.Data.FilteredMenuItem as FilteredMenuItem (item)
import Ribosome.Menu.Data.Menu (Menu(Menu))
import qualified Ribosome.Menu.Data.MenuItem as MenuItem (abbreviated)
import Ribosome.Menu.Data.MenuRenderEvent (MenuRenderEvent)
import qualified Ribosome.Menu.Data.MenuRenderEvent as MenuRenderEvent (MenuRenderEvent(..))
import Ribosome.Scratch (killScratch, setScratchContent)

marker :: Char
marker :: Char
marker =
  Char
'†'

markerConceal :: SyntaxItem
markerConceal :: SyntaxItem
markerConceal =
  SyntaxItem
item { $sel:siOptions:SyntaxItem :: [Text]
siOptions = [Text]
options, $sel:siParams:SyntaxItem :: Map Text Text
siParams = Map Text Text
params }
  where
    item :: SyntaxItem
item = Text -> Text -> SyntaxItem
syntaxMatch Text
"RibosomeMenuMarker" (Text -> Char -> Text
Text.snoc Text
"^" Char
marker)
    options :: [Text]
options = [Item [Text]
"conceal"]
    params :: Map Text Text
params = [(Text, Text)] -> Map Text Text
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Text
"nextgroup", Text
"RibosomeMenuMarkedLine")]

markedLine :: SyntaxItem
markedLine :: SyntaxItem
markedLine =
  SyntaxItem
item { $sel:siOptions:SyntaxItem :: [Text]
siOptions = [Text]
options }
  where
    item :: SyntaxItem
item = Text -> Text -> SyntaxItem
syntaxMatch Text
"RibosomeMenuMarkedLine" Text
".*$"
    options :: [Text]
options = [Item [Text]
"contained"]

hlMarkedLine :: HiLink
hlMarkedLine :: HiLink
hlMarkedLine =
  Text -> Text -> HiLink
HiLink Text
"RibosomeMenuMarkedLine" Text
"Tag"

menuSyntax :: Syntax
menuSyntax :: Syntax
menuSyntax =
  [SyntaxItem] -> [Highlight] -> [HiLink] -> Syntax
Syntax [Item [SyntaxItem]
SyntaxItem
markerConceal, Item [SyntaxItem]
SyntaxItem
markedLine] [] [Item [HiLink]
HiLink
hlMarkedLine]

withMarks :: [Int] -> [Text] -> [Text]
withMarks :: [Int] -> [Text] -> [Text]
withMarks =
  (Text -> Text) -> [Int] -> [Text] -> [Text]
forall a. (a -> a) -> [Int] -> [a] -> [a]
mapSelectors (Char -> Text -> Text
Text.cons Char
marker)

renderNvimMenu ::
  MonadRibo m =>
  NvimE e m =>
  ScratchOptions ->
  Scratch ->
  MenuRenderEvent m a i ->
  m ()
renderNvimMenu :: ScratchOptions -> Scratch -> MenuRenderEvent m a i -> m ()
renderNvimMenu ScratchOptions
_ Scratch
scratch (MenuRenderEvent.Quit QuitReason m a
_) =
  Scratch -> m ()
forall (m :: * -> *) e. (MonadRibo m, NvimE e m) => Scratch -> m ()
killScratch Scratch
scratch
renderNvimMenu ScratchOptions
options Scratch
scratch (MenuRenderEvent.Render Bool
changed (Menu [MenuItem i]
_ [FilteredMenuItem i]
allItems Int
selected [Int]
marked MenuFilter
_ Maybe Int
maxItems)) =
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
changed (ScratchOptions -> Scratch -> [Text] -> m ()
forall (t :: * -> *) e (m :: * -> *).
(Foldable t, NvimE e m) =>
ScratchOptions -> Scratch -> t Text -> m ()
setScratchContent ScratchOptions
options Scratch
scratch ([Text] -> [Text]
forall a. [a] -> [a]
reverse [Text]
text)) m () -> m () -> m ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
  Text -> m ()
forall a (m :: * -> *). (Loggable a, MonadRibo m) => a -> m ()
logDebug @Text Text
logMsg m () -> m () -> m ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
  m ()
updateCursor m () -> m () -> m ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
  m ()
forall e (m :: * -> *). NvimE e m => m ()
redraw
  where
    lineNumber :: Int
lineNumber =
      Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ [FilteredMenuItem i] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilteredMenuItem i]
items Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
selected Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
    text :: [Text]
text =
      [Int] -> [Text] -> [Text]
withMarks [Int]
marked (Getting Text (FilteredMenuItem i) Text
-> FilteredMenuItem i -> Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view ((MenuItem i -> Const Text (MenuItem i))
-> FilteredMenuItem i -> Const Text (FilteredMenuItem i)
forall c a. HasFilteredMenuItem c a => Lens' c (MenuItem a)
FilteredMenuItem.item ((MenuItem i -> Const Text (MenuItem i))
 -> FilteredMenuItem i -> Const Text (FilteredMenuItem i))
-> ((Text -> Const Text Text)
    -> MenuItem i -> Const Text (MenuItem i))
-> Getting Text (FilteredMenuItem i) Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Const Text Text) -> MenuItem i -> Const Text (MenuItem i)
forall c a. HasMenuItem c a => Lens' c Text
MenuItem.abbreviated) (FilteredMenuItem i -> Text) -> [FilteredMenuItem i] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [FilteredMenuItem i]
items)
    items :: [FilteredMenuItem i]
items =
      [FilteredMenuItem i] -> [FilteredMenuItem i]
limit [FilteredMenuItem i]
allItems
    limit :: [FilteredMenuItem i] -> [FilteredMenuItem i]
limit =
      ([FilteredMenuItem i] -> [FilteredMenuItem i])
-> (Int -> [FilteredMenuItem i] -> [FilteredMenuItem i])
-> Maybe Int
-> [FilteredMenuItem i]
-> [FilteredMenuItem i]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [FilteredMenuItem i] -> [FilteredMenuItem i]
forall a. a -> a
id Int -> [FilteredMenuItem i] -> [FilteredMenuItem i]
forall a. Int -> [a] -> [a]
take Maybe Int
maxItems
    updateCursor :: m ()
updateCursor =
      Window -> Int -> m ()
forall e (m :: * -> *). NvimE e m => Window -> Int -> m ()
setLine (Scratch -> Window
scratchWindow Scratch
scratch) Int
lineNumber
    logMsg :: Text
logMsg =
      Text
"updating menu cursor to line " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
lineNumber Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"; " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
selected Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show ([FilteredMenuItem i] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilteredMenuItem i]
items)