module Catalog where import qualified Data.Text as T import qualified System.Directory as D import qualified System.Posix as P import qualified System.Info as In data SearchDir = SearchDir { dirDepth ::Int, searchDir :: FilePath } deriving (Show, Eq, Ord) data Action = Action { actionSearchString :: T.Text, ioAction :: IOAction } data IOAction = OneParam (Cataloged -> IO ()) | TwoParam (Cataloged -> Cataloged -> IO ()) data Cataloged = Cataloged { inputType :: InputType, dirPath :: T.Text } deriving (Show, Eq, Ord) data InputType = Folder | File deriving (Show, Eq, Ord) instance Searchable Action where searchString = actionSearchString instance Searchable Cataloged where searchString = T.toLower . T.pack . reverse . takeWhile (/= '/') . reverse . T.unpack . dirPath instance Show Action where show = T.unpack . searchString instance Searchable T.Text where searchString = id class Searchable s where searchString :: s -> T.Text getCatalog :: IO [Cataloged] getCatalog = do absHomeDir <- D.getHomeDirectory searchCatalogItem SearchDir { dirDepth = 1, searchDir = absHomeDir } -- recursively crawl a directory to the desired depth searchCatalogItem :: SearchDir -> IO [Cataloged] searchCatalogItem (SearchDir depth path) = do asCatalogMaybe <- dirToCatalog path case (depth, asCatalogMaybe) of (_, Nothing) -> print path >> return [] (0, Just asCatalog) -> return [asCatalog] (_, Just asCatalog) -> case inputType asCatalog of File -> return [asCatalog] Folder -> do childPaths <- D.listDirectory path childCatalogs <- mconcat <$> mapM recSearchCatalog childPaths return $ asCatalog : childCatalogs where recSearchCatalog :: FilePath -> IO [Cataloged] recSearchCatalog childName = searchCatalogItem . SearchDir (pred depth) $ (path ++ "/" ++ childName) dirToCatalog :: FilePath -> IO (Maybe Cataloged) dirToCatalog path = do fileExists <- P.fileExist path inputTypeMaybe <- if fileExists then toInputType <$> P.getFileStatus path else return Nothing return $ (\inputType -> Cataloged { inputType = inputType, dirPath = T.pack path }) <$> inputTypeMaybe toInputType :: P.FileStatus -> Maybe InputType toInputType fileType | P.isDirectory fileType = Just Folder | P.isRegularFile fileType = Just Folder | otherwise = Nothing -- we only match the first one because the action is always the second thing -- that's selected, regardless of how many inputs the action takes -- validAction :: Action -> Cataloged -> Bool -- validAction action = (==) (head . inputs $ action) . inputType getActions :: Cataloged -> [Action] getActions cataloged = [ Action { actionSearchString = "move to trash", ioAction = OneParam $ \cataloged -> P.executeFile "mv" True [T.unpack . dirPath $ cataloged, "~/.Trash"] Nothing }, Action { actionSearchString = "move to", ioAction = TwoParam (\cataloged cataloged' -> P.executeFile "mv" True (map (T.unpack . dirPath) [cataloged, cataloged']) Nothing) } ] ++ case In.os of "darwin" -> darwinActions "linux" -> linuxActions linuxActions :: [Action] linuxActions = [ Action { actionSearchString = "open", ioAction = OneParam $ \cataloged -> P.executeFile "open" True [T.unpack . dirPath $ cataloged] Nothing } ] darwinActions :: [Action] darwinActions = [ Action { actionSearchString = "xfg-open", ioAction = OneParam $ \cataloged -> P.executeFile "open" True [T.unpack . dirPath $ cataloged] Nothing } ]