aboutsummaryrefslogtreecommitdiff
path: root/lib/Daffm/Action
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/Daffm/Action/Commands.hs7
-rw-r--r--lib/Daffm/Action/Core.hs49
2 files changed, 52 insertions, 4 deletions
diff --git a/lib/Daffm/Action/Commands.hs b/lib/Daffm/Action/Commands.hs
index a9cf691..35262df 100644
--- a/lib/Daffm/Action/Commands.hs
+++ b/lib/Daffm/Action/Commands.hs
@@ -9,7 +9,7 @@ import Control.Monad.IO.Class (MonadIO (liftIO))
import Daffm.Action.Cmdline
import Daffm.Action.Core
import Daffm.Types
-import Daffm.Utils (trimStart)
+import Daffm.Utils (trim, trimStart)
import Data.Bifunctor (Bifunctor (second))
import Data.Char (isSpace)
import Data.Maybe (fromMaybe)
@@ -45,6 +45,9 @@ parseCommand cmd = mkCmd . splitCmdArgs $ trimStart cmd
("cmdline-set", txt) -> Just $ CmdSetCmdline txt
("selection-toggle", _) -> Just CmdToggleSelection
("selection-clear", _) -> Just CmdClearSelection
+ ("search", term) -> Just $ CmdSearch $ trim term
+ ("search-next", _) -> Just $ CmdSearchNext 1
+ ("search-prev", _) -> Just $ CmdSearchNext (-1)
_ -> Nothing
readCommandLines' :: Text.Text -> IO [Text.Text]
@@ -83,6 +86,8 @@ processCommand CmdToggleSelection = toggleCurrentFileSelection
processCommand CmdClearSelection = clearFileSelections
processCommand CmdGoBack = goBackToParentDir
processCommand (CmdChain chain) = forM_ chain processCommand
+processCommand (CmdSearch term) = setSearchTerm term >> applySearch >> nextSearchMatch
+processCommand (CmdSearchNext change) = updateSearchIndex (+ change) >> nextSearchMatch
processCommand CmdNoop = pure ()
evaluateCommand :: Text.Text -> AppEvent ()
diff --git a/lib/Daffm/Action/Core.hs b/lib/Daffm/Action/Core.hs
index a8dad32..a726c77 100644
--- a/lib/Daffm/Action/Core.hs
+++ b/lib/Daffm/Action/Core.hs
@@ -13,6 +13,7 @@ import Daffm.Types (AppEvent, AppState (..), FileInfo (..), FilePathText, FileTy
import Data.Maybe (fromMaybe)
import qualified Data.Set as Set
import qualified Data.Text as Text
+import qualified Data.Vector as Vec
import System.Directory (getHomeDirectory)
import qualified System.Exit as Proc
import System.FilePath (takeDirectory)
@@ -24,6 +25,7 @@ modifyM f = get >>= f >>= put
loadDir :: FilePathText -> AppEvent ()
loadDir dir = do
modifyM (liftIO . (>>= filterInvalidSelections) . loadDirToState dir)
+ applySearch
reloadDir :: AppEvent ()
reloadDir = do
@@ -93,9 +95,7 @@ currentFile = do
toggleCurrentFileSelection :: AppEvent ()
toggleCurrentFileSelection = do
- currentFile >>= \case
- Just file -> modify $ toggleFileSelection (filePath file)
- Nothing -> pure ()
+ currentFile >>= maybe (pure ()) (modify . toggleFileSelection . filePath)
moveCurrent 1
clearFileSelections :: AppEvent ()
@@ -106,3 +106,46 @@ moveCurrent :: Int -> AppEvent ()
moveCurrent count = do
files <- gets stateFiles
modify $ \s -> s {stateFiles = L.listMoveBy count files}
+
+setSearchTerm :: Text.Text -> AppEvent ()
+setSearchTerm "" = modify (\st -> st {stateSearchTerm = Nothing, stateSearchIndex = 0})
+setSearchTerm term = modify (\st -> st {stateSearchTerm = Just term, stateSearchIndex = 0})
+
+applySearch :: AppEvent ()
+applySearch = get >>= apply
+ where
+ apply :: AppState -> AppEvent ()
+ apply (AppState {stateSearchTerm = Nothing}) =
+ modify
+ (\st -> st {stateSearchMatches = Vec.empty, stateSearchIndex = 0})
+ apply (AppState {stateSearchTerm = Just term, stateFiles}) = do
+ let search (_, FileInfo {fileName}) = Text.toLower term `Text.isInfixOf` Text.toLower fileName
+ let matches = Vec.map fst . Vec.filter search . Vec.indexed $ L.listElements stateFiles
+ modify
+ ( \st ->
+ st
+ { stateSearchMatches = matches,
+ stateSearchIndex = wrapSearchIndex st (stateSearchIndex st)
+ }
+ )
+
+nextSearchMatch :: AppEvent ()
+nextSearchMatch = do
+ st@(AppState {stateSearchMatches, stateFiles, stateSearchIndex}) <- get
+ let nextFiles =
+ if Vec.null stateSearchMatches
+ then stateFiles
+ else L.listMoveTo (stateSearchMatches Vec.! wrapSearchIndex st stateSearchIndex) stateFiles
+ modify (\st' -> st' {stateFiles = nextFiles})
+
+wrapSearchIndex :: AppState -> Int -> Int
+wrapSearchIndex (AppState {stateSearchMatches}) nextIndex =
+ let matchCount = length stateSearchMatches
+ in if
+ | nextIndex < 0 -> matchCount - 1
+ | nextIndex >= matchCount && matchCount /= 0 -> nextIndex `mod` matchCount
+ | otherwise -> nextIndex
+
+updateSearchIndex :: (Int -> Int) -> AppEvent ()
+updateSearchIndex upd =
+ modify (\st -> st {stateSearchIndex = wrapSearchIndex st $ upd $ stateSearchIndex st})