diff options
Diffstat (limited to '')
| -rw-r--r-- | lib/Daffm/Action/Commands.hs | 7 | ||||
| -rw-r--r-- | lib/Daffm/Action/Core.hs | 49 |
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}) |
