manatee-anything-0.0.2: Manatee/Plugin/Anything/AnythingLocate.hs
-- Author: Andy Stewart <lazycat.manatee@gmail.com>
-- Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
--
-- Copyright (C) 2010 Andy Stewart, all rights reserved.
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, DeriveDataTypeable, RankNTypes #-}
module Manatee.Plugin.Anything.AnythingLocate where
import DBus.Client hiding (Signal)
import Data.ByteString.UTF8 hiding (drop, length)
import Data.List
import Data.Typeable
import Manatee.Core.DBus
import Manatee.Core.FileOpenRule
import Manatee.Core.Types
import Manatee.Plugin.Anything.Anything
import Manatee.Plugin.Anything.Types
import Manatee.Toolkit.General.FilePath
import Manatee.Toolkit.General.Maybe
import Manatee.Toolkit.General.Misc
import Manatee.Toolkit.Gio.Gio
import System.Environment
import System.FilePath
import System.GIO.Enums
import System.GIO.File.FileInfo hiding (FileInfo)
import qualified Data.ByteString.Char8 as B
data FileInfo =
FileInfo {fileInfoPath :: ByteString
,fileInfoDisplayName :: String
,fileInfoContentType :: String
,fileInfoFileType :: FileType
,fileInfoSize :: String
} deriving Typeable
instance AnythingCandidate FileInfo where
candidateCommandName _ = ""
candidateFilterName a = fileInfoDisplayName a ++ " " ++ fileInfoSize a
candidateCompletionName a _ = fileInfoDisplayName a
candidateExpandName a input = do
home <- getEnv "HOME"
return $
if ("~" :: String) `isPrefixOf` input
-- Replace HOME with ~ if user input is beginning with ~
then '~' : drop (length home) (toString $ fileInfoPath a)
-- Otherwise keep user input.
else toString $ fileInfoPath a
-- | Search local files.
anythingLocate :: Anything
anythingLocate =
Anything {anythingColumnTitle = ["Locate", "Size"]
,anythingColumnFun = anythingLocateColumnFun
,anythingSearch = AnythingSearch (anythingLocateSearch False)
,anythingFilterRule = anythingLocateFilterRule
,anythingCompletionRule = takeFileName
,anythingInputDepend = True
,anythingCommandFun = anythingLocateCommandFun
,anythingCalculateDelay = 0
}
-- | Search local files.
anythingLocateSearch :: Bool -> AnythingInput -> Client -> IO [FileInfo]
anythingLocateSearch filterDir filepath _ = do
home <- getEnv "HOME"
let -- Expand '~' with HOME value.
path = if ("~" :: String) `isPrefixOf` filepath
then home ++ drop (length ("~" :: String)) filepath
else filepath
-- Try to get upper directory of current file path.
upperDir | hasTrailingPathSeparator path
= fromString path
| otherwise
= fromString $ getUpperDirectory path
anythingLocateGetFileInfos upperDir filterDir
-- | Get FileInfo.
anythingLocateGetFileInfos :: ByteString -> Bool -> IO [FileInfo]
anythingLocateGetFileInfos upperDir filterDir =
if directoryDoesExist upperDir -- get result.
then do
-- Get file infos.
infos <- do
fileInfos <- directoryGetFileInfos upperDir -- just search deep when upper directory exist.
return $
map (\info ->
FileInfo (B.concat [upperDir, fileInfoGetNameWithType info])
(fileInfoGetDisplayNameWithType info)
(maybeError (fileInfoGetContentType info)
"anythingInteractiveDirectorySearch - fileInfoGetContentType.")
(fileInfoGetFileType info)
(formatFileSizeForDisplay $ toInteger $ fileInfoGetSize info))
$ (\x ->
if filterDir
then filter (\x -> fileInfoGetFileType x == FileTypeDirectory) x
else x
) fileInfos
return $ sortBy (\ a b -> compareFileWithType
(fileInfoDisplayName a, fileInfoFileType a)
(fileInfoDisplayName b, fileInfoFileType b)
) infos
else return []
-- | Rule for filter file name.
anythingLocateFilterRule :: AnythingInput -> String -> Bool
anythingLocateFilterRule input candidate =
-- Current path is end by path separator?
hasTrailingPathSeparator input ||
-- Or have same prefix with filename.
(takeFileName input `isPrefixOf` candidate)
-- | Function for generate candidate column.
anythingLocateColumnFun :: [AnythingColumnFun]
anythingLocateColumnFun =
[fileInfoDisplayName . anythingCandidateUnpack
,fileInfoSize . anythingCandidateUnpack]
-- | Function to generate command list.
anythingLocateCommandFun :: AnythingCommandFun
anythingLocateCommandFun _ wrap _
| directoryDoesExist path
= return [("Open directory", anythingLocateActionOpenDirectory filepath)
,("Play directory", anythingLocateActionPlayDirectory filepath)]
| otherwise =
fileOpenRule filepath contentType
where path = fileInfoPath $ anythingCandidateUnpack wrap
filepath = toString path
contentType = fileInfoContentType $ anythingCandidateUnpack wrap
-- | Open file.
anythingLocateActionOpenFile :: FilePath -> Client -> IO ()
anythingLocateActionOpenFile path client =
mkDaemonSignal client NewTab (NewTabArgs "PageEditor" path)
-- | Open directory.
anythingLocateActionOpenDirectory :: FilePath -> Client -> IO ()
anythingLocateActionOpenDirectory path client =
mkDaemonSignal client NewTab (NewTabArgs "PageFileManager" path)
-- | Play directory.
anythingLocateActionPlayDirectory :: FilePath -> Client -> IO ()
anythingLocateActionPlayDirectory path client =
mkDaemonSignal client NewTab (NewTabArgs "PagePlayer" path)