{-# LANGUAGE TemplateHaskell #-}

-- | A simple brick app to search among the candidates from a vector of text and get the selection. By default the app doesn't do anything except
-- return a single selection but more complicated actions can be performed by using the `_hooks` which allow abitrary IO actions (due to `EventM` being a `MonadIO`)
-- in response to input events. The most convenient function to use the brick app are `selected` and related functions. `runApp` provides some more flexibility.
module Talash.Brick (-- * Types
                     Searcher (..) , SearchEvent (..) , SearchEnv (..) ,  EventHooks (..) , AppTheme (..) , AppSettings (..) , AppSettingsG (..) , CaseSensitivity (..)
                     -- * The Brick App and Helpers
                    , searchApp , defSettings , fuzzyFunctions , orderlessFunctions , runApp , runAppFromHandle , selected , selectedFromHandle
                    , selectedFromHandleWith , selectedFromFileNamesSorted , selectedFromFiles , selectedUsing , runSearch , makeChunks
                    -- * Default program
                    , run , run'
                     -- * Lenses
                     -- ** Searcher
                    , queryEditor , allMatches , matches , numMatches
                     -- ** SearchEvent
                    , matchedTop , totalMatches , term
                     -- ** SearchEnv
                    , candidates , eventSource
                     -- ** SearchFunctions
                    , makeMatcher , match , display
                     -- ** AppTheme
                    , prompt , themeAttrs , borderStyle
                     -- ** SearchSettings
                    , theme , hooks , defTheme , defHooks
                     -- * Exposed Internals
                    , handleKeyEvent , handleSearch , searcherWidget , initialSearcher , readVectorHandleWith)
where

import Data.Monoid.Colorful as C
import Data.Vector (unsafeIndex , elemIndex)
import GHC.Compact (Compact , compact , getCompact)
import qualified System.IO.Streams as I
import Talash.Brick.Internal
import Talash.Files
import Talash.Intro hiding (sort, on , take)

data AppTheme = AppTheme { AppTheme -> Text
_prompt :: Text -- ^ The prompt to display next to the editor.
                         , AppTheme -> [(AttrName, Attr)]
_themeAttrs :: [(AttrName, Attr)]  -- ^ This is used to construct the `attrMap` for the app. By default the used attarNmaes are
                                                              --  `listSelectedAttr` , `borderAttr` , \"Prompt\" , \"Highlight\" and \"Stats\"
                         , AppTheme -> BorderStyle
_borderStyle :: BorderStyle -- ^ The border style to use. By default `unicodeRounded`
                         }
makeLenses ''AppTheme

type AppSettings n a = AppSettingsG n a (Widget Bool) AppTheme

-- | The brick widget used to display the editor and the search result.
searcherWidget :: (KnownNat n , KnownNat m) => SearchEnv n a (Widget Bool) -> Text -> SearcherSized m a -> Widget Bool
searcherWidget :: forall (n :: Nat) (m :: Nat) a.
(KnownNat n, KnownNat m) =>
SearchEnv n a (Widget Bool)
-> Text -> SearcherSized m a -> Widget Bool
searcherWidget SearchEnv n a (Widget Bool)
env Text
p SearcherSized m a
s = forall n. Widget n -> Widget n
joinBorders forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Widget n -> Widget n
border forall a b. (a -> b) -> a -> b
$ forall n. [Widget n] -> Widget n
vBox [forall n.
(Ord n, Show n) =>
Bool -> Text -> Editor Text n -> Widget n -> Widget n
searchWidgetAux Bool
True Text
p (SearcherSized m a
s forall s a. s -> Getting a s a -> a
^. forall (n :: Nat) a. Lens' (SearcherSized n a) (Editor Text Bool)
queryEditor) (forall n. AttrName -> Widget n -> Widget n
withAttr (String -> AttrName
attrName String
"Stats") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Text -> Widget n
txt  forall a b. (a -> b) -> a -> b
$ String -> Text
pack (forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ SearcherSized m a
s forall s a. s -> Getting a s a -> a
^. forall (n :: Nat) a. Lens' (SearcherSized n a) Int
numMatches))
                                                     , forall n. Widget n
hBorder , forall n (m :: Nat) (l :: Nat) a.
(Ord n, Show n, KnownNat m, KnownNat l) =>
SearchEnv l a (Widget n)
-> Text
-> MatcherSized m a
-> Bool
-> GenericList n MatchSetG (ScoredMatchSized m)
-> Widget n
listWithHighlights SearchEnv n a (Widget Bool)
env Text
"➜ " (SearcherSized m a
s forall s a. s -> Getting a s a -> a
^. forall (n :: Nat) a. Lens' (SearcherSized n a) (MatcherSized n a)
matcher) Bool
False (SearcherSized m a
s forall s a. s -> Getting a s a -> a
^. forall (n :: Nat) a.
Lens'
  (SearcherSized n a)
  (GenericList Bool MatchSetG (ScoredMatchSized n))
matches)]

defThemeAttrs :: [(AttrName, Attr)]
defThemeAttrs :: [(AttrName, Attr)]
defThemeAttrs = [ (AttrName
listSelectedAttr, Attr -> Style -> Attr
withStyle (Color -> Attr
bg Color
white) Style
bold) , (String -> AttrName
attrName String
"Prompt" , Attr -> Style -> Attr
withStyle (Color
white Color -> Color -> Attr
`on` Color
blue) Style
bold)
                , (String -> AttrName
attrName String
"Highlight" , Attr -> Style -> Attr
withStyle (Color -> Attr
fg Color
blue) Style
bold) ,  (String -> AttrName
attrName String
"Stats" , Color -> Attr
fg Color
blue) ,  (AttrName
borderAttr , Color -> Attr
fg Color
cyan)]

defTheme ::AppTheme
defTheme :: AppTheme
defTheme = AppTheme {_prompt :: Text
_prompt = Text
"Find: " , _themeAttrs :: [(AttrName, Attr)]
_themeAttrs = [(AttrName, Attr)]
defThemeAttrs , _borderStyle :: BorderStyle
_borderStyle = BorderStyle
unicodeRounded}

-- | Default settings. Uses blue for various highlights and cyan for borders. All the hooks except keyHook which is `handleKeyEvent` are trivial.
{-# INLINE defSettings#-}
defSettings :: KnownNat n => AppSettings n a
defSettings :: forall (n :: Nat) a. KnownNat n => AppSettings n a
defSettings = forall (n :: Nat) a b t.
t
-> ReaderT (SearchEnv n a b) EventHooks (Searcher a)
-> Proxy n
-> Int
-> (SearchReport -> Bool)
-> AppSettingsG n a b t
AppSettings AppTheme
defTheme (forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (\SearchEnv n a (Widget Bool)
e -> forall a. EventHooks a
defHooks {keyHook :: Key -> [Modifier] -> EventM Bool (Searcher a) ()
keyHook = forall (n :: Nat) a c b.
KnownNat n =>
SearchEnv n a c -> Key -> [Modifier] -> EventM Bool (Searcher b) ()
handleKeyEvent SearchEnv n a (Widget Bool)
e})) forall {k} (t :: k). Proxy t
Proxy Int
4096
                          (\SearchReport
r -> SearchReport
r forall s a. s -> Getting a s a -> a
^. Lens' SearchReport Ocassion
ocassion forall a. Eq a => a -> a -> Bool
== Ocassion
QueryDone)

-- | Tha app itself. `selected` and the related functions are probably more convenient for embedding into a larger program.
searchApp ::KnownNat n => AppSettings n a -> SearchEnv n a (Widget Bool) -> App (Searcher a) (SearchEvent a) Bool
searchApp :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchEnv n a (Widget Bool)
-> App (Searcher a) (SearchEvent a) Bool
searchApp (AppSettings AppTheme
th ReaderT (SearchEnv n a (Widget Bool)) EventHooks (Searcher a)
hks Proxy n
_ Int
_ SearchReport -> Bool
_) SearchEnv n a (Widget Bool)
env  = App {appDraw :: Searcher a -> [Widget Bool]
appDraw = Searcher a -> [Widget Bool]
ad , appChooseCursor :: Searcher a -> [CursorLocation Bool] -> Maybe (CursorLocation Bool)
appChooseCursor = forall s n. s -> [CursorLocation n] -> Maybe (CursorLocation n)
showFirstCursor , appHandleEvent :: BrickEvent Bool (SearchEvent a) -> EventM Bool (Searcher a) ()
appHandleEvent = forall {n}.
BrickEvent n (SearchEvent a) -> EventM Bool (Searcher a) ()
he , appStartEvent :: EventM Bool (Searcher a) ()
appStartEvent = EventM Bool (Searcher a) ()
as , appAttrMap :: Searcher a -> AttrMap
appAttrMap = forall {b}. b -> AttrMap
am}
  where
    ad :: Searcher a -> [Widget Bool]
ad (Searcher SearcherSized n a
s)                                  = (forall a. a -> [a] -> [a]
:[]) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. BorderStyle -> Widget n -> Widget n
withBorderStyle (AppTheme
th forall s a. s -> Getting a s a -> a
^. Lens' AppTheme BorderStyle
borderStyle) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat) (m :: Nat) a.
(KnownNat n, KnownNat m) =>
SearchEnv n a (Widget Bool)
-> Text -> SearcherSized m a -> Widget Bool
searcherWidget SearchEnv n a (Widget Bool)
env (AppTheme
th forall s a. s -> Getting a s a -> a
^. Lens' AppTheme Text
prompt) forall a b. (a -> b) -> a -> b
$ SearcherSized n a
s
    as :: EventM Bool (Searcher a) ()
as                                               = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (forall (n :: Nat) a b.
KnownNat n =>
SearchEnv n a b -> Text -> IO ()
sendQuery SearchEnv n a (Widget Bool)
env Text
"")
    am :: b -> AttrMap
am                                               = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ Attr -> [(AttrName, Attr)] -> AttrMap
attrMap Attr
defAttr (AppTheme
th forall s a. s -> Getting a s a -> a
^. Lens' AppTheme [(AttrName, Attr)]
themeAttrs)
    hk :: EventHooks (Searcher a)
hk                                               = forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT (SearchEnv n a (Widget Bool)) EventHooks (Searcher a)
hks SearchEnv n a (Widget Bool)
env
    he :: BrickEvent n (SearchEvent a) -> EventM Bool (Searcher a) ()
he (VtyEvent (EvKey Key
k [Modifier]
m))                      = forall a. EventHooks a -> Key -> [Modifier] -> EventM Bool a ()
keyHook EventHooks (Searcher a)
hk Key
k [Modifier]
m
    he (VtyEvent (EvMouseDown Int
i Int
j Button
b [Modifier]
m))            = forall a.
EventHooks a
-> Int -> Int -> Button -> [Modifier] -> EventM Bool a ()
mouseDownHook   EventHooks (Searcher a)
hk Int
i Int
j Button
b [Modifier]
m
    he (VtyEvent (EvMouseUp   Int
i Int
j Maybe Button
b  ))            = forall a.
EventHooks a -> Int -> Int -> Maybe Button -> EventM Bool a ()
mouseUpHook     EventHooks (Searcher a)
hk Int
i Int
j Maybe Button
b
    he (VtyEvent (EvPaste     ByteString
b      ))            = forall a. EventHooks a -> ByteString -> EventM Bool a ()
pasteHook       EventHooks (Searcher a)
hk     ByteString
b
    he (VtyEvent  Event
EvGainedFocus       )            = forall a. EventHooks a -> EventM Bool a ()
focusGainedHook EventHooks (Searcher a)
hk
    he (VtyEvent  Event
EvLostFocus         )            = forall a. EventHooks a -> EventM Bool a ()
focusLostHook   EventHooks (Searcher a)
hk
    he (AppEvent e :: SearchEvent a
e@(SearchEvent SearchEventSized n a
e'))               = forall a. SearchEvent a -> EventM Bool (Searcher a) ()
handleSearch SearchEvent a
e
    he BrickEvent n (SearchEvent a)
_                                           = forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

-- | Run app with given settings and return the final Searcher state.
runApp :: KnownNat n => AppSettings n a -> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Searcher a)
runApp :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Searcher a)
runApp AppSettings n a
s SearchFunctions a (Widget Bool)
f Chunks n
c =     (\BChan (SearchEvent a)
b -> (\SearchEnv n a (Widget Bool)
env -> forall (n :: Nat) a b. KnownNat n => SearchEnv n a b -> IO ()
startSearcher SearchEnv n a (Widget Bool)
env forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall a b. IO a -> IO b -> IO a
finally (forall n b e. Ord n => App b e n -> BChan e -> b -> IO b
theMain (forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchEnv n a (Widget Bool)
-> App (Searcher a) (SearchEvent a) Bool
searchApp AppSettings n a
s SearchEnv n a (Widget Bool)
env) BChan (SearchEvent a)
b forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a (n :: Nat). KnownNat n => SearcherSized n a -> Searcher a
Searcher forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat) a c.
SearchEnv n a c -> BChan (SearchEvent a) -> SearcherSized 0 a
initialSearcher SearchEnv n a (Widget Bool)
env forall a b. (a -> b) -> a -> b
$ BChan (SearchEvent a)
b) (forall (n :: Nat) a b. KnownNat n => SearchEnv n a b -> IO ()
stopSearcher SearchEnv n a (Widget Bool)
env))
               forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (n :: Nat) a b.
KnownNat n =>
SearchFunctions a b
-> Int
-> (forall (n1 :: Nat) (m :: Nat).
    (KnownNat n1, KnownNat m) =>
    Chunks n1
    -> SearchReport -> MatcherSized m a -> MatchSetSized m -> IO ())
-> Chunks n
-> IO (SearchEnv n a b)
searchEnv SearchFunctions a (Widget Bool)
f (AppSettings n a
s forall s a. s -> Getting a s a -> a
^. forall (n :: Nat) a b t. Lens' (AppSettingsG n a b t) Int
maximumMatches) (forall (m :: Nat) a b c.
KnownNat m =>
(SearchReport -> Bool)
-> BChan (SearchEvent a)
-> c
-> SearchReport
-> MatcherSized m a
-> MatchSetSized m
-> IO ()
generateSearchEvent (AppSettings n a
s forall s a. s -> Getting a s a -> a
^. forall (n :: Nat) a b t.
Lens' (AppSettingsG n a b t) (SearchReport -> Bool)
eventStrategy) BChan (SearchEvent a)
b) Chunks n
c) forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a. Int -> IO (BChan a)
newBChan Int
8

-- | Run app with a vector that contains lines read from a handle and return the final Searcher state.
runAppFromHandle :: KnownNat n => AppSettings n a -> SearchFunctions a (Widget Bool) -> Handle -> IO (Searcher a)
runAppFromHandle :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Handle -> IO (Searcher a)
runAppFromHandle AppSettings n a
s SearchFunctions a (Widget Bool)
f = forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Searcher a)
runApp AppSettings n a
s SearchFunctions a (Widget Bool)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Compact a -> a
getCompact forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< forall a. a -> IO (Compact a)
compact forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Chunks n -> Chunks n
forceChunks forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< forall (n :: Nat). KnownNat n => Proxy n -> Handle -> IO (Chunks n)
chunksFromHandle (AppSettings n a
s forall s a. s -> Getting a s a -> a
^. forall (n :: Nat) a b t. Lens' (AppSettingsG n a b t) (Proxy n)
chunkSize)

-- | Run app with a vector that contains lines read from a handle and return the final Searcher state.
runAppFromVector :: KnownNat n =>  AppSettings n a -> SearchFunctions a (Widget Bool) -> Vector Text -> IO (Searcher a)
runAppFromVector :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool)
-> Vector Text
-> IO (Searcher a)
runAppFromVector AppSettings n a
s SearchFunctions a (Widget Bool)
f = forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Searcher a)
runApp AppSettings n a
s SearchFunctions a (Widget Bool)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Compact a -> a
getCompact forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< forall a. a -> IO (Compact a)
compact forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Chunks n -> Chunks n
forceChunks forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Vector Text -> Chunks n
makeChunks

-- | Run app and return the text of the selection if there is one else Nothing.
selected :: KnownNat n => AppSettings n a -> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Maybe Text)
selected :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Maybe Text)
selected AppSettings n a
s SearchFunctions a (Widget Bool)
f = (\Chunks n
c -> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (forall (n :: Nat) a.
KnownNat n =>
Chunks n -> Searcher a -> Maybe Text
selectedElement Chunks n
c) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Searcher a)
runApp AppSettings n a
s SearchFunctions a (Widget Bool)
f forall a b. (a -> b) -> a -> b
$ Chunks n
c) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Compact a -> a
getCompact forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< forall a. a -> IO (Compact a)
compact forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Chunks n -> Chunks n
forceChunks

-- | Same as `selected` but reads the vector from the supplied handle.
selectedFromHandle :: KnownNat n => AppSettings n a -> SearchFunctions a (Widget Bool) -> Handle -> IO (Maybe Text)
selectedFromHandle :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Handle -> IO (Maybe Text)
selectedFromHandle AppSettings n a
s SearchFunctions a (Widget Bool)
f = forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Maybe Text)
selected AppSettings n a
s SearchFunctions a (Widget Bool)
f forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< forall (n :: Nat). KnownNat n => Proxy n -> Handle -> IO (Chunks n)
chunksFromHandle (AppSettings n a
s forall s a. s -> Getting a s a -> a
^. forall (n :: Nat) a b t. Lens' (AppSettingsG n a b t) (Proxy n)
chunkSize)

-- | Same as `selectedFromHandle` but allows for transforming the lines read and the final vector with supplied functions. See also `readVectorHandleWith`.
selectedFromHandleWith :: KnownNat n => (Text -> Text) -> (Vector Text -> Vector Text) -> AppSettings n a -> SearchFunctions a (Widget Bool) -> Handle -> IO (Maybe Text)
selectedFromHandleWith :: forall (n :: Nat) a.
KnownNat n =>
(Text -> Text)
-> (Vector Text -> Vector Text)
-> AppSettings n a
-> SearchFunctions a (Widget Bool)
-> Handle
-> IO (Maybe Text)
selectedFromHandleWith Text -> Text
w Vector Text -> Vector Text
t AppSettings n a
s SearchFunctions a (Widget Bool)
f = forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Maybe Text)
selected AppSettings n a
s SearchFunctions a (Widget Bool)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Vector Text -> Chunks n
makeChunks forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< (Text -> Text)
-> (Vector Text -> Vector Text) -> Handle -> IO (Vector Text)
readVectorHandleWith Text -> Text
w Vector Text -> Vector Text
t

-- | Another variation on `selectedFromHandle`. See `fileNamesSorted` for what happens to read vector.
selectedFromFileNamesSorted :: KnownNat n => AppSettings n a -> SearchFunctions a (Widget Bool) -> Handle -> IO (Maybe Text)
selectedFromFileNamesSorted :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Handle -> IO (Maybe Text)
selectedFromFileNamesSorted AppSettings n a
s SearchFunctions a (Widget Bool)
f = forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Maybe Text)
selected AppSettings n a
s SearchFunctions a (Widget Bool)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
.  forall (n :: Nat). KnownNat n => Vector Text -> Chunks n
makeChunks forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< Handle -> IO (Vector Text)
fileNamesSorted

-- | Version of `selected` for file search using a simple implementation of searching file trees from "Talash.Files". Better to use either other
-- libraries like @unix-recursive@ or external programs like @fd@ for more complicated tasks.
selectedFromFiles :: KnownNat n => AppSettings n a -> SearchFunctions a (Widget Bool) -> [FindInDirs] -> IO (Maybe Text)
selectedFromFiles :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool)
-> [FindInDirs]
-> IO (Maybe Text)
selectedFromFiles AppSettings n a
s SearchFunctions a (Widget Bool)
f = forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Maybe Text)
selected AppSettings n a
s SearchFunctions a (Widget Bool)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Chunks n -> Chunks n
forceChunks forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Vector Text -> Chunks n
makeChunks forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FileTree Text -> Vector Text
flatten forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< [FindInDirs] -> IO (Vector (FileTree Text))
findFilesInDirs

selectedUsing :: KnownNat n => AppSettings n a -> SearchFunctions a (Widget Bool) -> (a -> Text) -> Vector a -> IO (Maybe a)
selectedUsing :: forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool)
-> (a -> Text)
-> Vector a
-> IO (Maybe a)
selectedUsing AppSettings n a
s SearchFunctions a (Widget Bool)
f a -> Text
t Vector a
v = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (forall a. Vector a -> Int -> a
unsafeIndex Vector a
v) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Eq a => a -> Vector a -> Maybe Int
`elemIndex` Vector Text
w) forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Maybe Text)
selected AppSettings n a
s SearchFunctions a (Widget Bool)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Vector Text -> Chunks n
makeChunks forall a b. (a -> b) -> a -> b
$ Vector Text
w
  where
    w :: Vector Text
w = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map a -> Text
t Vector a
v

-- | A version of `selected` that puts the selected text on the stdout.
runSearch :: AppSettings 64 a -> SearchFunctions a (Widget Bool) -> IO ()
runSearch :: forall a.
AppSettings 64 a -> SearchFunctions a (Widget Bool) -> IO ()
runSearch AppSettings 64 a
s SearchFunctions a (Widget Bool)
f = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) Text -> IO ()
putStrLn forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (n :: Nat) a.
KnownNat n =>
AppSettings n a
-> SearchFunctions a (Widget Bool) -> Chunks n -> IO (Maybe Text)
selected AppSettings 64 a
s SearchFunctions a (Widget Bool)
f forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (n :: Nat). KnownNat n => InputStream Text -> IO (Chunks n)
chunksFromStream forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< InputStream ByteString -> IO (InputStream Text)
I.decodeUtf8 forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< InputStream ByteString -> IO (InputStream ByteString)
I.lines InputStream ByteString
I.stdin

-- | The backend for `run`
run' :: [String] -> IO ()
run' :: [String] -> IO ()
run' []                 = forall a.
AppSettings 64 a -> SearchFunctions a (Widget Bool) -> IO ()
runSearch forall (n :: Nat) a. KnownNat n => AppSettings n a
defSettings (forall b. CaseSensitivity -> SearchFunctions Int b
orderlessFunctions CaseSensitivity
IgnoreCase)
run' [String
"fuzzy"]          = forall a.
AppSettings 64 a -> SearchFunctions a (Widget Bool) -> IO ()
runSearch forall (n :: Nat) a. KnownNat n => AppSettings n a
defSettings (forall b. CaseSensitivity -> SearchFunctions MatchPart b
fuzzyFunctions CaseSensitivity
IgnoreCase)
run' [String
"orderless"]      = forall a.
AppSettings 64 a -> SearchFunctions a (Widget Bool) -> IO ()
runSearch forall (n :: Nat) a. KnownNat n => AppSettings n a
defSettings (forall b. CaseSensitivity -> SearchFunctions Int b
orderlessFunctions CaseSensitivity
IgnoreCase)
run' [String]
xs                 = (\Term
t -> forall a. (a -> IO ()) -> Term -> Colored a -> IO ()
C.printColored Text -> IO ()
putStr Term
t Colored Text
usageString) forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO Term
C.getTerm

usageString :: Colored Text
usageString :: Colored Text
usageString =    Colored Text
"talash tui is a set of command for a tui searcher/selector interface. It reads the input from the stdin to generate candidates to search for,"
              forall a. Semigroup a => a -> a -> a
<> Colored Text
" one from each line and outputs the selected candidate (if there is one) on the stdout.\n"
              forall a. Semigroup a => a -> a -> a
<> forall a. Color -> Colored a -> Colored a
C.Fg Color
C.Blue Colored Text
"talash tui" forall a. Semigroup a => a -> a -> a
<> Colored Text
": Run the tui with the default orderless style of searching.\n"
              forall a. Semigroup a => a -> a -> a
<> forall a. Color -> Colored a -> Colored a
C.Fg Color
C.Blue Colored Text
"talash tui fuzzy" forall a. Semigroup a => a -> a -> a
<> Colored Text
": Run the tui with fuzzy style for searching.\n"
              forall a. Semigroup a => a -> a -> a
<> forall a. Color -> Colored a -> Colored a
C.Fg Color
C.Blue Colored Text
"talash tui orderless" forall a. Semigroup a => a -> a -> a
<>  Colored Text
": Run the tui with the default orderless style of searching.\n"

-- | Defualt program for the brick app that reads candidates from stdin and prints the selected text to the stdout. Can be called from the executable with
-- @talash tui@ which uses the orderless style. The search style can be set explicitly by calling @talash tui fuzzy@ or @talash tui orderless@
run :: IO ()
run :: IO ()
run = [String] -> IO ()
run' forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO [String]
getArgs