{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Brick.Widgets.FileBrowser
(
FileBrowser
, FileInfo(..)
, FileStatus(..)
, FileType(..)
, newFileBrowser
, selectNonDirectories
, selectDirectories
, setWorkingDirectory
, getWorkingDirectory
, updateFileBrowserSearch
, setFileBrowserEntryFilter
, actionFileBrowserBeginSearch
, actionFileBrowserSelectEnter
, actionFileBrowserSelectCurrent
, actionFileBrowserListPageUp
, actionFileBrowserListPageDown
, actionFileBrowserListHalfPageUp
, actionFileBrowserListHalfPageDown
, actionFileBrowserListTop
, actionFileBrowserListBottom
, actionFileBrowserListNext
, actionFileBrowserListPrev
, handleFileBrowserEvent
, maybeSelectCurrentEntry
, renderFileBrowser
, fileBrowserCursor
, fileBrowserIsSearching
, fileBrowserSelection
, fileBrowserException
, fileBrowserSelectable
, fileInfoFileType
, fileBrowserAttr
, fileBrowserCurrentDirectoryAttr
, fileBrowserSelectionInfoAttr
, fileBrowserSelectedAttr
, fileBrowserDirectoryAttr
, fileBrowserBlockDeviceAttr
, fileBrowserRegularFileAttr
, fileBrowserCharacterDeviceAttr
, fileBrowserNamedPipeAttr
, fileBrowserSymbolicLinkAttr
, fileBrowserUnixSocketAttr
, fileTypeMatch
, fileExtensionMatch
, fileBrowserSelectableL
, fileInfoFilenameL
, fileInfoSanitizedFilenameL
, fileInfoFilePathL
, fileInfoFileStatusL
, fileInfoLinkTargetTypeL
, fileStatusSizeL
, fileStatusFileTypeL
, fileBrowserEntryFilterG
, fileBrowserWorkingDirectoryG
, fileBrowserEntriesG
, fileBrowserLatestResultsG
, fileBrowserSelectedFilesG
, fileBrowserNameG
, fileBrowserSearchStringG
, fileBrowserExceptionG
, fileBrowserSelectableG
, prettyFileSize
, entriesForDirectory
, getFileInfo
)
where
import qualified Control.Exception as E
import Control.Monad (forM, when)
import Control.Monad.IO.Class (liftIO)
import Data.Char (toLower, isPrint)
import Data.Foldable (for_)
import Data.Maybe (fromMaybe, isJust, fromJust)
import qualified Data.Foldable as F
import qualified Data.Text as T
#if !(MIN_VERSION_base(4,11,0))
import Data.Monoid
#endif
import Data.Int (Int64)
import Data.List (sortBy, isSuffixOf)
import qualified Data.Set as Set
import qualified Data.Vector as V
import Lens.Micro
import Lens.Micro.Mtl ((%=))
import Lens.Micro.TH (lensRules, generateUpdateableOptics)
import qualified Graphics.Vty as Vty
import qualified System.Directory as D
import qualified System.PosixCompat.Files as U
import qualified System.PosixCompat.Types as U
import qualified System.FilePath as FP
import Text.Printf (printf)
import Brick.Types
import Brick.AttrMap (AttrName, attrName)
import Brick.Widgets.Core
import Brick.Widgets.List
data FileBrowser n =
FileBrowser { forall n. FileBrowser n -> String
fileBrowserWorkingDirectory :: FilePath
, forall n. FileBrowser n -> List n FileInfo
fileBrowserEntries :: List n FileInfo
, forall n. FileBrowser n -> [FileInfo]
fileBrowserLatestResults :: [FileInfo]
, forall n. FileBrowser n -> Set String
fileBrowserSelectedFiles :: Set.Set String
, forall n. FileBrowser n -> n
fileBrowserName :: n
, forall n. FileBrowser n -> Maybe (FileInfo -> Bool)
fileBrowserEntryFilter :: Maybe (FileInfo -> Bool)
, forall n. FileBrowser n -> Maybe Text
fileBrowserSearchString :: Maybe T.Text
, forall n. FileBrowser n -> Maybe IOException
fileBrowserException :: Maybe E.IOException
, forall n. FileBrowser n -> FileInfo -> Bool
fileBrowserSelectable :: FileInfo -> Bool
}
instance Named (FileBrowser n) n where
getName :: FileBrowser n -> n
getName = List n FileInfo -> n
forall a n. Named a n => a -> n
getName (List n FileInfo -> n)
-> (FileBrowser n -> List n FileInfo) -> FileBrowser n -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileBrowser n -> List n FileInfo
forall n. FileBrowser n -> List n FileInfo
fileBrowserEntries
data FileStatus =
FileStatus { FileStatus -> Int64
fileStatusSize :: Int64
, FileStatus -> Maybe FileType
fileStatusFileType :: Maybe FileType
}
deriving (Int -> FileStatus -> ShowS
[FileStatus] -> ShowS
FileStatus -> String
(Int -> FileStatus -> ShowS)
-> (FileStatus -> String)
-> ([FileStatus] -> ShowS)
-> Show FileStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileStatus -> ShowS
showsPrec :: Int -> FileStatus -> ShowS
$cshow :: FileStatus -> String
show :: FileStatus -> String
$cshowList :: [FileStatus] -> ShowS
showList :: [FileStatus] -> ShowS
Show, FileStatus -> FileStatus -> Bool
(FileStatus -> FileStatus -> Bool)
-> (FileStatus -> FileStatus -> Bool) -> Eq FileStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileStatus -> FileStatus -> Bool
== :: FileStatus -> FileStatus -> Bool
$c/= :: FileStatus -> FileStatus -> Bool
/= :: FileStatus -> FileStatus -> Bool
Eq)
data FileInfo =
FileInfo { FileInfo -> String
fileInfoFilename :: String
, FileInfo -> String
fileInfoSanitizedFilename :: String
, FileInfo -> String
fileInfoFilePath :: FilePath
, FileInfo -> Either IOException FileStatus
fileInfoFileStatus :: Either E.IOException FileStatus
, FileInfo -> Maybe FileType
fileInfoLinkTargetType :: Maybe FileType
}
deriving (Int -> FileInfo -> ShowS
[FileInfo] -> ShowS
FileInfo -> String
(Int -> FileInfo -> ShowS)
-> (FileInfo -> String) -> ([FileInfo] -> ShowS) -> Show FileInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileInfo -> ShowS
showsPrec :: Int -> FileInfo -> ShowS
$cshow :: FileInfo -> String
show :: FileInfo -> String
$cshowList :: [FileInfo] -> ShowS
showList :: [FileInfo] -> ShowS
Show, FileInfo -> FileInfo -> Bool
(FileInfo -> FileInfo -> Bool)
-> (FileInfo -> FileInfo -> Bool) -> Eq FileInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileInfo -> FileInfo -> Bool
== :: FileInfo -> FileInfo -> Bool
$c/= :: FileInfo -> FileInfo -> Bool
/= :: FileInfo -> FileInfo -> Bool
Eq)
data FileType =
RegularFile
| BlockDevice
| CharacterDevice
| NamedPipe
| Directory
| SymbolicLink
| UnixSocket
deriving (ReadPrec [FileType]
ReadPrec FileType
Int -> ReadS FileType
ReadS [FileType]
(Int -> ReadS FileType)
-> ReadS [FileType]
-> ReadPrec FileType
-> ReadPrec [FileType]
-> Read FileType
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS FileType
readsPrec :: Int -> ReadS FileType
$creadList :: ReadS [FileType]
readList :: ReadS [FileType]
$creadPrec :: ReadPrec FileType
readPrec :: ReadPrec FileType
$creadListPrec :: ReadPrec [FileType]
readListPrec :: ReadPrec [FileType]
Read, Int -> FileType -> ShowS
[FileType] -> ShowS
FileType -> String
(Int -> FileType -> ShowS)
-> (FileType -> String) -> ([FileType] -> ShowS) -> Show FileType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileType -> ShowS
showsPrec :: Int -> FileType -> ShowS
$cshow :: FileType -> String
show :: FileType -> String
$cshowList :: [FileType] -> ShowS
showList :: [FileType] -> ShowS
Show, FileType -> FileType -> Bool
(FileType -> FileType -> Bool)
-> (FileType -> FileType -> Bool) -> Eq FileType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileType -> FileType -> Bool
== :: FileType -> FileType -> Bool
$c/= :: FileType -> FileType -> Bool
/= :: FileType -> FileType -> Bool
Eq)
suffixLenses ''FileBrowser
suffixLensesWith "G" (lensRules & generateUpdateableOptics .~ False) ''FileBrowser
suffixLenses ''FileInfo
suffixLenses ''FileStatus
newFileBrowser :: (FileInfo -> Bool)
-> n
-> Maybe FilePath
-> IO (FileBrowser n)
newFileBrowser :: forall n.
(FileInfo -> Bool) -> n -> Maybe String -> IO (FileBrowser n)
newFileBrowser FileInfo -> Bool
selPredicate n
name Maybe String
mCwd = do
String
initialCwd <- ShowS
FP.normalise ShowS -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> case Maybe String
mCwd of
Just String
path -> String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return String
path
Maybe String
Nothing -> IO String
D.getCurrentDirectory
let b :: FileBrowser n
b = FileBrowser { fileBrowserWorkingDirectory :: String
fileBrowserWorkingDirectory = String
initialCwd
, fileBrowserEntries :: List n FileInfo
fileBrowserEntries = n -> Vector FileInfo -> Int -> List n FileInfo
forall (t :: * -> *) n e.
Foldable t =>
n -> t e -> Int -> GenericList n t e
list n
name Vector FileInfo
forall a. Monoid a => a
mempty Int
1
, fileBrowserLatestResults :: [FileInfo]
fileBrowserLatestResults = [FileInfo]
forall a. Monoid a => a
mempty
, fileBrowserSelectedFiles :: Set String
fileBrowserSelectedFiles = Set String
forall a. Monoid a => a
mempty
, fileBrowserName :: n
fileBrowserName = n
name
, fileBrowserEntryFilter :: Maybe (FileInfo -> Bool)
fileBrowserEntryFilter = Maybe (FileInfo -> Bool)
forall a. Maybe a
Nothing
, fileBrowserSearchString :: Maybe Text
fileBrowserSearchString = Maybe Text
forall a. Maybe a
Nothing
, fileBrowserException :: Maybe IOException
fileBrowserException = Maybe IOException
forall a. Maybe a
Nothing
, fileBrowserSelectable :: FileInfo -> Bool
fileBrowserSelectable = FileInfo -> Bool
selPredicate
}
String -> FileBrowser n -> IO (FileBrowser n)
forall n. String -> FileBrowser n -> IO (FileBrowser n)
setWorkingDirectory String
initialCwd FileBrowser n
b
selectNonDirectories :: FileInfo -> Bool
selectNonDirectories :: FileInfo -> Bool
selectNonDirectories FileInfo
i =
case FileInfo -> Maybe FileType
fileInfoFileType FileInfo
i of
Just FileType
Directory -> Bool
False
Just FileType
SymbolicLink ->
case FileInfo -> Maybe FileType
fileInfoLinkTargetType FileInfo
i of
Just FileType
Directory -> Bool
False
Maybe FileType
_ -> Bool
True
Maybe FileType
_ -> Bool
True
selectDirectories :: FileInfo -> Bool
selectDirectories :: FileInfo -> Bool
selectDirectories FileInfo
i =
case FileInfo -> Maybe FileType
fileInfoFileType FileInfo
i of
Just FileType
Directory -> Bool
True
Just FileType
SymbolicLink -> FileInfo -> Maybe FileType
fileInfoLinkTargetType FileInfo
i Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
== FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory
Maybe FileType
_ -> Bool
False
setFileBrowserEntryFilter :: Maybe (FileInfo -> Bool) -> FileBrowser n -> FileBrowser n
setFileBrowserEntryFilter :: forall n.
Maybe (FileInfo -> Bool) -> FileBrowser n -> FileBrowser n
setFileBrowserEntryFilter Maybe (FileInfo -> Bool)
f FileBrowser n
b =
FileBrowser n -> FileBrowser n
forall n. FileBrowser n -> FileBrowser n
applyFilterAndSearch (FileBrowser n -> FileBrowser n) -> FileBrowser n -> FileBrowser n
forall a b. (a -> b) -> a -> b
$ FileBrowser n
b FileBrowser n -> (FileBrowser n -> FileBrowser n) -> FileBrowser n
forall a b. a -> (a -> b) -> b
& (Maybe (FileInfo -> Bool) -> Identity (Maybe (FileInfo -> Bool)))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(Maybe (FileInfo -> Bool) -> f (Maybe (FileInfo -> Bool)))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntryFilterL ((Maybe (FileInfo -> Bool) -> Identity (Maybe (FileInfo -> Bool)))
-> FileBrowser n -> Identity (FileBrowser n))
-> Maybe (FileInfo -> Bool) -> FileBrowser n -> FileBrowser n
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe (FileInfo -> Bool)
f
setWorkingDirectory :: FilePath -> FileBrowser n -> IO (FileBrowser n)
setWorkingDirectory :: forall n. String -> FileBrowser n -> IO (FileBrowser n)
setWorkingDirectory String
path FileBrowser n
b = do
Either IOException [FileInfo]
entriesResult <- IO [FileInfo] -> IO (Either IOException [FileInfo])
forall e a. Exception e => IO a -> IO (Either e a)
E.try (IO [FileInfo] -> IO (Either IOException [FileInfo]))
-> IO [FileInfo] -> IO (Either IOException [FileInfo])
forall a b. (a -> b) -> a -> b
$ String -> IO [FileInfo]
entriesForDirectory String
path
let ([FileInfo]
entries, Maybe IOException
exc) = case Either IOException [FileInfo]
entriesResult of
Left (IOException
e::E.IOException) -> ([], IOException -> Maybe IOException
forall a. a -> Maybe a
Just IOException
e)
Right [FileInfo]
es -> ([FileInfo]
es, Maybe IOException
forall a. Maybe a
Nothing)
[FileInfo]
allEntries <- if String
path String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"/" then [FileInfo] -> IO [FileInfo]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [FileInfo]
entries else do
Either IOException FileInfo
parentResult <- IO FileInfo -> IO (Either IOException FileInfo)
forall e a. Exception e => IO a -> IO (Either e a)
E.try (IO FileInfo -> IO (Either IOException FileInfo))
-> IO FileInfo -> IO (Either IOException FileInfo)
forall a b. (a -> b) -> a -> b
$ String -> IO FileInfo
parentOf String
path
[FileInfo] -> IO [FileInfo]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([FileInfo] -> IO [FileInfo]) -> [FileInfo] -> IO [FileInfo]
forall a b. (a -> b) -> a -> b
$ case Either IOException FileInfo
parentResult of
Left (IOException
_::E.IOException) -> [FileInfo]
entries
Right FileInfo
parent -> FileInfo
parent FileInfo -> [FileInfo] -> [FileInfo]
forall a. a -> [a] -> [a]
: [FileInfo]
entries
FileBrowser n -> IO (FileBrowser n)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (FileBrowser n -> IO (FileBrowser n))
-> FileBrowser n -> IO (FileBrowser n)
forall a b. (a -> b) -> a -> b
$ [FileInfo] -> FileBrowser n -> FileBrowser n
forall n. [FileInfo] -> FileBrowser n -> FileBrowser n
setEntries [FileInfo]
allEntries FileBrowser n
b
FileBrowser n -> (FileBrowser n -> FileBrowser n) -> FileBrowser n
forall a b. a -> (a -> b) -> b
& (String -> Identity String)
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(String -> f String) -> FileBrowser n -> f (FileBrowser n)
fileBrowserWorkingDirectoryL ((String -> Identity String)
-> FileBrowser n -> Identity (FileBrowser n))
-> String -> FileBrowser n -> FileBrowser n
forall s t a b. ASetter s t a b -> b -> s -> t
.~ String
path
FileBrowser n -> (FileBrowser n -> FileBrowser n) -> FileBrowser n
forall a b. a -> (a -> b) -> b
& (Maybe IOException -> Identity (Maybe IOException))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(Maybe IOException -> f (Maybe IOException))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserExceptionL ((Maybe IOException -> Identity (Maybe IOException))
-> FileBrowser n -> Identity (FileBrowser n))
-> Maybe IOException -> FileBrowser n -> FileBrowser n
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe IOException
exc
FileBrowser n -> (FileBrowser n -> FileBrowser n) -> FileBrowser n
forall a b. a -> (a -> b) -> b
& (Set String -> Identity (Set String))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(Set String -> f (Set String))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSelectedFilesL ((Set String -> Identity (Set String))
-> FileBrowser n -> Identity (FileBrowser n))
-> Set String -> FileBrowser n -> FileBrowser n
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Set String
forall a. Monoid a => a
mempty
parentOf :: FilePath -> IO FileInfo
parentOf :: String -> IO FileInfo
parentOf String
path = String -> String -> IO FileInfo
getFileInfo String
".." (String -> IO FileInfo) -> String -> IO FileInfo
forall a b. (a -> b) -> a -> b
$ ShowS
FP.takeDirectory String
path
getFileInfo :: String
-> FilePath
-> IO FileInfo
getFileInfo :: String -> String -> IO FileInfo
getFileInfo String
name = [String] -> String -> IO FileInfo
go []
where
go :: [String] -> String -> IO FileInfo
go [String]
history String
fullPath = do
String
filePath <- String -> IO String
D.makeAbsolute String
fullPath
Either IOException FileStatus
statusResult <- IO FileStatus -> IO (Either IOException FileStatus)
forall e a. Exception e => IO a -> IO (Either e a)
E.try (IO FileStatus -> IO (Either IOException FileStatus))
-> IO FileStatus -> IO (Either IOException FileStatus)
forall a b. (a -> b) -> a -> b
$ String -> IO FileStatus
U.getSymbolicLinkStatus String
filePath
let stat :: Either IOException FileStatus
stat = do
FileStatus
status <- Either IOException FileStatus
statusResult
let U.COff Int64
sz = FileStatus -> COff
U.fileSize FileStatus
status
FileStatus -> Either IOException FileStatus
forall a. a -> Either IOException a
forall (m :: * -> *) a. Monad m => a -> m a
return FileStatus { fileStatusFileType :: Maybe FileType
fileStatusFileType = FileStatus -> Maybe FileType
fileTypeFromStatus FileStatus
status
, fileStatusSize :: Int64
fileStatusSize = Int64
sz
}
Maybe FileType
targetTy <- case FileStatus -> Maybe FileType
fileStatusFileType (FileStatus -> Maybe FileType)
-> Either IOException FileStatus
-> Either IOException (Maybe FileType)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either IOException FileStatus
stat of
Right (Just FileType
SymbolicLink) -> do
Either SomeException String
targetPathResult <- IO String -> IO (Either SomeException String)
forall e a. Exception e => IO a -> IO (Either e a)
E.try (IO String -> IO (Either SomeException String))
-> IO String -> IO (Either SomeException String)
forall a b. (a -> b) -> a -> b
$ String -> IO String
U.readSymbolicLink String
filePath
case Either SomeException String
targetPathResult of
Left (SomeException
_::E.SomeException) -> Maybe FileType -> IO (Maybe FileType)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe FileType
forall a. Maybe a
Nothing
Right String
targetPath ->
if String
targetPath String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
history
then Maybe FileType -> IO (Maybe FileType)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe FileType
forall a. Maybe a
Nothing
else do
FileInfo
targetInfo <- IO FileInfo -> IO FileInfo
forall a. IO a -> IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FileInfo -> IO FileInfo) -> IO FileInfo -> IO FileInfo
forall a b. (a -> b) -> a -> b
$ [String] -> String -> IO FileInfo
go (String
fullPath String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
history) String
targetPath
case FileInfo -> Either IOException FileStatus
fileInfoFileStatus FileInfo
targetInfo of
Right (FileStatus Int64
_ Maybe FileType
targetTy) -> Maybe FileType -> IO (Maybe FileType)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe FileType
targetTy
Either IOException FileStatus
_ -> Maybe FileType -> IO (Maybe FileType)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe FileType
forall a. Maybe a
Nothing
Either IOException (Maybe FileType)
_ -> Maybe FileType -> IO (Maybe FileType)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe FileType
forall a. Maybe a
Nothing
FileInfo -> IO FileInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return FileInfo { fileInfoFilename :: String
fileInfoFilename = String
name
, fileInfoFilePath :: String
fileInfoFilePath = String
filePath
, fileInfoSanitizedFilename :: String
fileInfoSanitizedFilename = ShowS
sanitizeFilename String
name
, fileInfoFileStatus :: Either IOException FileStatus
fileInfoFileStatus = Either IOException FileStatus
stat
, fileInfoLinkTargetType :: Maybe FileType
fileInfoLinkTargetType = Maybe FileType
targetTy
}
fileInfoFileType :: FileInfo -> Maybe FileType
fileInfoFileType :: FileInfo -> Maybe FileType
fileInfoFileType FileInfo
i =
case FileInfo -> Either IOException FileStatus
fileInfoFileStatus FileInfo
i of
Left IOException
_ -> Maybe FileType
forall a. Maybe a
Nothing
Right FileStatus
stat -> FileStatus -> Maybe FileType
fileStatusFileType FileStatus
stat
getWorkingDirectory :: FileBrowser n -> FilePath
getWorkingDirectory :: forall n. FileBrowser n -> String
getWorkingDirectory = FileBrowser n -> String
forall n. FileBrowser n -> String
fileBrowserWorkingDirectory
setEntries :: [FileInfo] -> FileBrowser n -> FileBrowser n
setEntries :: forall n. [FileInfo] -> FileBrowser n -> FileBrowser n
setEntries [FileInfo]
es FileBrowser n
b =
FileBrowser n -> FileBrowser n
forall n. FileBrowser n -> FileBrowser n
applyFilterAndSearch (FileBrowser n -> FileBrowser n) -> FileBrowser n -> FileBrowser n
forall a b. (a -> b) -> a -> b
$ FileBrowser n
b FileBrowser n -> (FileBrowser n -> FileBrowser n) -> FileBrowser n
forall a b. a -> (a -> b) -> b
& ([FileInfo] -> Identity [FileInfo])
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
([FileInfo] -> f [FileInfo]) -> FileBrowser n -> f (FileBrowser n)
fileBrowserLatestResultsL (([FileInfo] -> Identity [FileInfo])
-> FileBrowser n -> Identity (FileBrowser n))
-> [FileInfo] -> FileBrowser n -> FileBrowser n
forall s t a b. ASetter s t a b -> b -> s -> t
.~ [FileInfo]
es
fileBrowserIsSearching :: FileBrowser n -> Bool
fileBrowserIsSearching :: forall n. FileBrowser n -> Bool
fileBrowserIsSearching FileBrowser n
b = Maybe Text -> Bool
forall a. Maybe a -> Bool
isJust (Maybe Text -> Bool) -> Maybe Text -> Bool
forall a b. (a -> b) -> a -> b
$ FileBrowser n
bFileBrowser n
-> Getting (Maybe Text) (FileBrowser n) (Maybe Text) -> Maybe Text
forall s a. s -> Getting a s a -> a
^.Getting (Maybe Text) (FileBrowser n) (Maybe Text)
forall n (f :: * -> *).
Functor f =>
(Maybe Text -> f (Maybe Text))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSearchStringL
fileBrowserSelection :: FileBrowser n -> [FileInfo]
fileBrowserSelection :: forall n. FileBrowser n -> [FileInfo]
fileBrowserSelection FileBrowser n
b =
let getEntry :: String -> FileInfo
getEntry String
filename = Maybe FileInfo -> FileInfo
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe FileInfo -> FileInfo) -> Maybe FileInfo -> FileInfo
forall a b. (a -> b) -> a -> b
$ (FileInfo -> Bool) -> [FileInfo] -> Maybe FileInfo
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
F.find ((String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
filename) (String -> Bool) -> (FileInfo -> String) -> FileInfo -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileInfo -> String
fileInfoFilename) ([FileInfo] -> Maybe FileInfo) -> [FileInfo] -> Maybe FileInfo
forall a b. (a -> b) -> a -> b
$ FileBrowser n
bFileBrowser n
-> Getting [FileInfo] (FileBrowser n) [FileInfo] -> [FileInfo]
forall s a. s -> Getting a s a -> a
^.Getting [FileInfo] (FileBrowser n) [FileInfo]
forall n (f :: * -> *).
Functor f =>
([FileInfo] -> f [FileInfo]) -> FileBrowser n -> f (FileBrowser n)
fileBrowserLatestResultsL
in (String -> FileInfo) -> [String] -> [FileInfo]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> FileInfo
getEntry ([String] -> [FileInfo]) -> [String] -> [FileInfo]
forall a b. (a -> b) -> a -> b
$ Set String -> [String]
forall a. Set a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList (Set String -> [String]) -> Set String -> [String]
forall a b. (a -> b) -> a -> b
$ FileBrowser n
bFileBrowser n
-> Getting (Set String) (FileBrowser n) (Set String) -> Set String
forall s a. s -> Getting a s a -> a
^.Getting (Set String) (FileBrowser n) (Set String)
forall n (f :: * -> *).
Functor f =>
(Set String -> f (Set String))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSelectedFilesL
updateFileBrowserSearch :: (Maybe T.Text -> Maybe T.Text)
-> FileBrowser n
-> FileBrowser n
updateFileBrowserSearch :: forall n.
(Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
updateFileBrowserSearch Maybe Text -> Maybe Text
f FileBrowser n
b =
let old :: Maybe Text
old = FileBrowser n
bFileBrowser n
-> Getting (Maybe Text) (FileBrowser n) (Maybe Text) -> Maybe Text
forall s a. s -> Getting a s a -> a
^.Getting (Maybe Text) (FileBrowser n) (Maybe Text)
forall n (f :: * -> *).
Functor f =>
(Maybe Text -> f (Maybe Text))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSearchStringL
new :: Maybe Text
new = Maybe Text -> Maybe Text
f (Maybe Text -> Maybe Text) -> Maybe Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ FileBrowser n
bFileBrowser n
-> Getting (Maybe Text) (FileBrowser n) (Maybe Text) -> Maybe Text
forall s a. s -> Getting a s a -> a
^.Getting (Maybe Text) (FileBrowser n) (Maybe Text)
forall n (f :: * -> *).
Functor f =>
(Maybe Text -> f (Maybe Text))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSearchStringL
oldLen :: Int
oldLen = Int -> (Text -> Int) -> Maybe Text -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
0 Text -> Int
T.length Maybe Text
old
newLen :: Int
newLen = Int -> (Text -> Int) -> Maybe Text -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
0 Text -> Int
T.length Maybe Text
new
in if Maybe Text
old Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe Text
new
then FileBrowser n
b
else if Int
oldLen Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
newLen
then FileBrowser n
b FileBrowser n -> (FileBrowser n -> FileBrowser n) -> FileBrowser n
forall a b. a -> (a -> b) -> b
& (Maybe Text -> Identity (Maybe Text))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(Maybe Text -> f (Maybe Text))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSearchStringL ((Maybe Text -> Identity (Maybe Text))
-> FileBrowser n -> Identity (FileBrowser n))
-> Maybe Text -> FileBrowser n -> FileBrowser n
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe Text
new
else FileBrowser n -> FileBrowser n
forall n. FileBrowser n -> FileBrowser n
applyFilterAndSearch (FileBrowser n -> FileBrowser n) -> FileBrowser n -> FileBrowser n
forall a b. (a -> b) -> a -> b
$ FileBrowser n
b FileBrowser n -> (FileBrowser n -> FileBrowser n) -> FileBrowser n
forall a b. a -> (a -> b) -> b
& (Maybe Text -> Identity (Maybe Text))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(Maybe Text -> f (Maybe Text))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSearchStringL ((Maybe Text -> Identity (Maybe Text))
-> FileBrowser n -> Identity (FileBrowser n))
-> Maybe Text -> FileBrowser n -> FileBrowser n
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe Text
new
applyFilterAndSearch :: FileBrowser n -> FileBrowser n
applyFilterAndSearch :: forall n. FileBrowser n -> FileBrowser n
applyFilterAndSearch FileBrowser n
b =
let filterMatch :: FileInfo -> Bool
filterMatch = (FileInfo -> Bool) -> Maybe (FileInfo -> Bool) -> FileInfo -> Bool
forall a. a -> Maybe a -> a
fromMaybe (Bool -> FileInfo -> Bool
forall a b. a -> b -> a
const Bool
True) (FileBrowser n
bFileBrowser n
-> Getting
(Maybe (FileInfo -> Bool))
(FileBrowser n)
(Maybe (FileInfo -> Bool))
-> Maybe (FileInfo -> Bool)
forall s a. s -> Getting a s a -> a
^.Getting
(Maybe (FileInfo -> Bool))
(FileBrowser n)
(Maybe (FileInfo -> Bool))
forall n (f :: * -> *).
Functor f =>
(Maybe (FileInfo -> Bool) -> f (Maybe (FileInfo -> Bool)))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntryFilterL)
searchMatch :: FileInfo -> Bool
searchMatch = (FileInfo -> Bool)
-> (Text -> FileInfo -> Bool) -> Maybe Text -> FileInfo -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Bool -> FileInfo -> Bool
forall a b. a -> b -> a
const Bool
True)
(\Text
search FileInfo
i -> Text -> Text
T.toLower Text
search Text -> Text -> Bool
`T.isInfixOf` String -> Text
T.pack (Char -> Char
toLower (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FileInfo -> String
fileInfoSanitizedFilename FileInfo
i))
(FileBrowser n
bFileBrowser n
-> Getting (Maybe Text) (FileBrowser n) (Maybe Text) -> Maybe Text
forall s a. s -> Getting a s a -> a
^.Getting (Maybe Text) (FileBrowser n) (Maybe Text)
forall n (f :: * -> *).
Functor f =>
(Maybe Text -> f (Maybe Text))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSearchStringL)
match :: FileInfo -> Bool
match FileInfo
i = FileInfo -> Bool
filterMatch FileInfo
i Bool -> Bool -> Bool
&& FileInfo -> Bool
searchMatch FileInfo
i
matching :: [FileInfo]
matching = (FileInfo -> Bool) -> [FileInfo] -> [FileInfo]
forall a. (a -> Bool) -> [a] -> [a]
filter FileInfo -> Bool
match ([FileInfo] -> [FileInfo]) -> [FileInfo] -> [FileInfo]
forall a b. (a -> b) -> a -> b
$ FileBrowser n
bFileBrowser n
-> Getting [FileInfo] (FileBrowser n) [FileInfo] -> [FileInfo]
forall s a. s -> Getting a s a -> a
^.Getting [FileInfo] (FileBrowser n) [FileInfo]
forall n (f :: * -> *).
Functor f =>
([FileInfo] -> f [FileInfo]) -> FileBrowser n -> f (FileBrowser n)
fileBrowserLatestResultsL
in FileBrowser n
b { fileBrowserEntries = list (b^.fileBrowserNameL) (V.fromList matching) 1 }
prettyFileSize :: Int64
-> T.Text
prettyFileSize :: Int64 -> Text
prettyFileSize Int64
i
| Int64
i Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
2 Int64 -> Int64 -> Int64
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int64
40::Int64) = String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Double -> String
format (Int64
i Int64 -> Double -> Double
`divBy` (Double
2 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Double
40)) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"T"
| Int64
i Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
2 Int64 -> Int64 -> Int64
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int64
30::Int64) = String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Double -> String
format (Int64
i Int64 -> Double -> Double
`divBy` (Double
2 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Double
30)) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"G"
| Int64
i Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
2 Int64 -> Int64 -> Int64
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int64
20::Int64) = String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Double -> String
format (Int64
i Int64 -> Double -> Double
`divBy` (Double
2 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Double
20)) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"M"
| Int64
i Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
2 Int64 -> Int64 -> Int64
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int64
10::Int64) = String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Double -> String
format (Int64
i Int64 -> Double -> Double
`divBy` (Double
2 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Double
10)) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"K"
| Bool
otherwise = String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Int64 -> String
forall a. Show a => a -> String
show Int64
i String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" bytes"
where
format :: Double -> String
format = String -> Double -> String
forall r. PrintfType r => String -> r
printf String
"%0.1f"
divBy :: Int64 -> Double -> Double
divBy :: Int64 -> Double -> Double
divBy Int64
a Double
b = ((Int64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
a) :: Double) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
b
entriesForDirectory :: FilePath -> IO [FileInfo]
entriesForDirectory :: String -> IO [FileInfo]
entriesForDirectory String
rawPath = do
String
path <- String -> IO String
D.makeAbsolute String
rawPath
[String]
dirContents <- String -> IO [String]
D.listDirectory String
path
[FileInfo]
infos <- [String] -> (String -> IO FileInfo) -> IO [FileInfo]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [String]
dirContents ((String -> IO FileInfo) -> IO [FileInfo])
-> (String -> IO FileInfo) -> IO [FileInfo]
forall a b. (a -> b) -> a -> b
$ \String
f -> do
String -> String -> IO FileInfo
getFileInfo String
f (String
path String -> ShowS
FP.</> String
f)
let dirsFirst :: FileInfo -> FileInfo -> Ordering
dirsFirst FileInfo
a FileInfo
b = if FileInfo -> Maybe FileType
fileInfoFileType FileInfo
a Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
== FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory Bool -> Bool -> Bool
&&
FileInfo -> Maybe FileType
fileInfoFileType FileInfo
b Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
== FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory
then String -> String -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Char -> Char
toLower (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FileInfo -> String
fileInfoFilename FileInfo
a)
(Char -> Char
toLower (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FileInfo -> String
fileInfoFilename FileInfo
b)
else if FileInfo -> Maybe FileType
fileInfoFileType FileInfo
a Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
== FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory Bool -> Bool -> Bool
&&
FileInfo -> Maybe FileType
fileInfoFileType FileInfo
b Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
/= FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory
then Ordering
LT
else if FileInfo -> Maybe FileType
fileInfoFileType FileInfo
b Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
== FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory Bool -> Bool -> Bool
&&
FileInfo -> Maybe FileType
fileInfoFileType FileInfo
a Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
/= FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory
then Ordering
GT
else String -> String -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Char -> Char
toLower (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FileInfo -> String
fileInfoFilename FileInfo
a)
(Char -> Char
toLower (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FileInfo -> String
fileInfoFilename FileInfo
b)
allEntries :: [FileInfo]
allEntries = (FileInfo -> FileInfo -> Ordering) -> [FileInfo] -> [FileInfo]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy FileInfo -> FileInfo -> Ordering
dirsFirst [FileInfo]
infos
[FileInfo] -> IO [FileInfo]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [FileInfo]
allEntries
fileTypeFromStatus :: U.FileStatus -> Maybe FileType
fileTypeFromStatus :: FileStatus -> Maybe FileType
fileTypeFromStatus FileStatus
s =
if | FileStatus -> Bool
U.isBlockDevice FileStatus
s -> FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
BlockDevice
| FileStatus -> Bool
U.isCharacterDevice FileStatus
s -> FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
CharacterDevice
| FileStatus -> Bool
U.isNamedPipe FileStatus
s -> FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
NamedPipe
| FileStatus -> Bool
U.isRegularFile FileStatus
s -> FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
RegularFile
| FileStatus -> Bool
U.isDirectory FileStatus
s -> FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory
| FileStatus -> Bool
U.isSocket FileStatus
s -> FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
UnixSocket
| FileStatus -> Bool
U.isSymbolicLink FileStatus
s -> FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
SymbolicLink
| Bool
otherwise -> Maybe FileType
forall a. Maybe a
Nothing
fileBrowserCursor :: FileBrowser n -> Maybe FileInfo
fileBrowserCursor :: forall n. FileBrowser n -> Maybe FileInfo
fileBrowserCursor FileBrowser n
b = (Int, FileInfo) -> FileInfo
forall a b. (a, b) -> b
snd ((Int, FileInfo) -> FileInfo)
-> Maybe (Int, FileInfo) -> Maybe FileInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericList n Vector FileInfo -> Maybe (Int, FileInfo)
forall (t :: * -> *) e n.
(Splittable t, Traversable t, Semigroup (t e)) =>
GenericList n t e -> Maybe (Int, e)
listSelectedElement (FileBrowser n
bFileBrowser n
-> Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> GenericList n Vector FileInfo
forall s a. s -> Getting a s a -> a
^.Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL)
actionFileBrowserBeginSearch :: EventM n (FileBrowser n) ()
actionFileBrowserBeginSearch :: forall n. EventM n (FileBrowser n) ()
actionFileBrowserBeginSearch =
(FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ())
-> (FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$ (Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
forall n.
(Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
updateFileBrowserSearch (Maybe Text -> Maybe Text -> Maybe Text
forall a b. a -> b -> a
const (Maybe Text -> Maybe Text -> Maybe Text)
-> Maybe Text -> Maybe Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"")
actionFileBrowserSelectEnter :: EventM n (FileBrowser n) ()
actionFileBrowserSelectEnter :: forall n. EventM n (FileBrowser n) ()
actionFileBrowserSelectEnter =
EventM n (FileBrowser n) ()
forall n. EventM n (FileBrowser n) ()
maybeSelectCurrentEntry
actionFileBrowserSelectCurrent :: EventM n (FileBrowser n) ()
actionFileBrowserSelectCurrent :: forall n. EventM n (FileBrowser n) ()
actionFileBrowserSelectCurrent =
EventM n (FileBrowser n) ()
forall n. EventM n (FileBrowser n) ()
selectCurrentEntry
actionFileBrowserListPageUp :: Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPageUp :: forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPageUp =
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) ()
-> EventM n (FileBrowser n) ()
forall c.
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) c)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) c
-> EventM n (FileBrowser n) c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
zoom (GenericList n Vector FileInfo
-> Focusing
(StateT (EventState n) IO) () (GenericList n Vector FileInfo))
-> FileBrowser n
-> Focusing (StateT (EventState n) IO) () (FileBrowser n)
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL EventM n (GenericList n Vector FileInfo) ()
forall (t :: * -> *) n e.
(Foldable t, Splittable t, Ord n) =>
EventM n (GenericList n t e) ()
listMovePageUp
actionFileBrowserListPageDown :: Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPageDown :: forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPageDown =
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) ()
-> EventM n (FileBrowser n) ()
forall c.
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) c)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) c
-> EventM n (FileBrowser n) c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
zoom (GenericList n Vector FileInfo
-> Focusing
(StateT (EventState n) IO) () (GenericList n Vector FileInfo))
-> FileBrowser n
-> Focusing (StateT (EventState n) IO) () (FileBrowser n)
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL EventM n (GenericList n Vector FileInfo) ()
forall (t :: * -> *) n e.
(Foldable t, Splittable t, Ord n) =>
EventM n (GenericList n t e) ()
listMovePageDown
actionFileBrowserListHalfPageUp :: Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListHalfPageUp :: forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListHalfPageUp =
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) ()
-> EventM n (FileBrowser n) ()
forall c.
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) c)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) c
-> EventM n (FileBrowser n) c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
zoom (GenericList n Vector FileInfo
-> Focusing
(StateT (EventState n) IO) () (GenericList n Vector FileInfo))
-> FileBrowser n
-> Focusing (StateT (EventState n) IO) () (FileBrowser n)
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL (Double -> EventM n (GenericList n Vector FileInfo) ()
forall (t :: * -> *) n m e.
(Foldable t, Splittable t, Ord n, RealFrac m) =>
m -> EventM n (GenericList n t e) ()
listMoveByPages (-Double
0.5::Double))
actionFileBrowserListHalfPageDown :: Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListHalfPageDown :: forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListHalfPageDown =
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) ()
-> EventM n (FileBrowser n) ()
forall c.
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) c)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) c
-> EventM n (FileBrowser n) c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
zoom (GenericList n Vector FileInfo
-> Focusing
(StateT (EventState n) IO) () (GenericList n Vector FileInfo))
-> FileBrowser n
-> Focusing (StateT (EventState n) IO) () (FileBrowser n)
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL (Double -> EventM n (GenericList n Vector FileInfo) ()
forall (t :: * -> *) n m e.
(Foldable t, Splittable t, Ord n, RealFrac m) =>
m -> EventM n (GenericList n t e) ()
listMoveByPages (Double
0.5::Double))
actionFileBrowserListTop :: Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListTop :: forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListTop =
(List n FileInfo -> Identity (List n FileInfo))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL ((List n FileInfo -> Identity (List n FileInfo))
-> FileBrowser n -> Identity (FileBrowser n))
-> (List n FileInfo -> List n FileInfo)
-> EventM n (FileBrowser n) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Int -> List n FileInfo -> List n FileInfo
forall (t :: * -> *) n e.
(Foldable t, Splittable t) =>
Int -> GenericList n t e -> GenericList n t e
listMoveTo Int
0
actionFileBrowserListBottom :: Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListBottom :: forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListBottom = do
FileBrowser n
b <- EventM n (FileBrowser n) (FileBrowser n)
forall s (m :: * -> *). MonadState s m => m s
get
let sz :: Int
sz = Vector FileInfo -> Int
forall a. Vector a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (GenericList n Vector FileInfo -> Vector FileInfo
forall n (t :: * -> *) e. GenericList n t e -> t e
listElements (GenericList n Vector FileInfo -> Vector FileInfo)
-> GenericList n Vector FileInfo -> Vector FileInfo
forall a b. (a -> b) -> a -> b
$ FileBrowser n
bFileBrowser n
-> Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> GenericList n Vector FileInfo
forall s a. s -> Getting a s a -> a
^.Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL)
(GenericList n Vector FileInfo
-> Identity (GenericList n Vector FileInfo))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL ((GenericList n Vector FileInfo
-> Identity (GenericList n Vector FileInfo))
-> FileBrowser n -> Identity (FileBrowser n))
-> (GenericList n Vector FileInfo -> GenericList n Vector FileInfo)
-> EventM n (FileBrowser n) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Int
-> GenericList n Vector FileInfo -> GenericList n Vector FileInfo
forall (t :: * -> *) n e.
(Foldable t, Splittable t) =>
Int -> GenericList n t e -> GenericList n t e
listMoveTo (Int
sz Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
actionFileBrowserListNext :: Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListNext :: forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListNext =
(List n FileInfo -> Identity (List n FileInfo))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL ((List n FileInfo -> Identity (List n FileInfo))
-> FileBrowser n -> Identity (FileBrowser n))
-> (List n FileInfo -> List n FileInfo)
-> EventM n (FileBrowser n) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Int -> List n FileInfo -> List n FileInfo
forall (t :: * -> *) n e.
(Foldable t, Splittable t) =>
Int -> GenericList n t e -> GenericList n t e
listMoveBy Int
1
actionFileBrowserListPrev :: Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPrev :: forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPrev =
(List n FileInfo -> Identity (List n FileInfo))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL ((List n FileInfo -> Identity (List n FileInfo))
-> FileBrowser n -> Identity (FileBrowser n))
-> (List n FileInfo -> List n FileInfo)
-> EventM n (FileBrowser n) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Int -> List n FileInfo -> List n FileInfo
forall (t :: * -> *) n e.
(Foldable t, Splittable t) =>
Int -> GenericList n t e -> GenericList n t e
listMoveBy (-Int
1)
handleFileBrowserEvent :: (Ord n) => Vty.Event -> EventM n (FileBrowser n) ()
handleFileBrowserEvent :: forall n. Ord n => Event -> EventM n (FileBrowser n) ()
handleFileBrowserEvent Event
e = do
FileBrowser n
b <- EventM n (FileBrowser n) (FileBrowser n)
forall s (m :: * -> *). MonadState s m => m s
get
if FileBrowser n -> Bool
forall n. FileBrowser n -> Bool
fileBrowserIsSearching FileBrowser n
b
then Event -> EventM n (FileBrowser n) ()
forall n. Ord n => Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventSearching Event
e
else Event -> EventM n (FileBrowser n) ()
forall n. Ord n => Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventNormal Event
e
safeInit :: T.Text -> T.Text
safeInit :: Text -> Text
safeInit Text
t | Text -> Int
T.length Text
t Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Text
t
| Bool
otherwise = HasCallStack => Text -> Text
Text -> Text
T.init Text
t
handleFileBrowserEventSearching :: (Ord n) => Vty.Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventSearching :: forall n. Ord n => Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventSearching Event
e =
case Event
e of
Vty.EvKey (Vty.KChar Char
'c') [Modifier
Vty.MCtrl] ->
(FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ())
-> (FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$ (Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
forall n.
(Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
updateFileBrowserSearch (Maybe Text -> Maybe Text -> Maybe Text
forall a b. a -> b -> a
const Maybe Text
forall a. Maybe a
Nothing)
Vty.EvKey Key
Vty.KEsc [] ->
(FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ())
-> (FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$ (Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
forall n.
(Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
updateFileBrowserSearch (Maybe Text -> Maybe Text -> Maybe Text
forall a b. a -> b -> a
const Maybe Text
forall a. Maybe a
Nothing)
Vty.EvKey Key
Vty.KBS [] ->
(FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ())
-> (FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$ (Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
forall n.
(Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
updateFileBrowserSearch ((Text -> Text) -> Maybe Text -> Maybe Text
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Text
safeInit)
Vty.EvKey Key
Vty.KEnter [] -> do
EventM n (FileBrowser n) ()
forall n. EventM n (FileBrowser n) ()
maybeSelectCurrentEntry
(FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ())
-> (FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$ (Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
forall n.
(Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
updateFileBrowserSearch (Maybe Text -> Maybe Text -> Maybe Text
forall a b. a -> b -> a
const Maybe Text
forall a. Maybe a
Nothing)
Vty.EvKey (Vty.KChar Char
c) [] ->
(FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ())
-> (FileBrowser n -> FileBrowser n) -> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$ (Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
forall n.
(Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
updateFileBrowserSearch ((Text -> Text) -> Maybe Text -> Maybe Text
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Text -> Char -> Text) -> Char -> Text -> Text
forall a b c. (a -> b -> c) -> b -> a -> c
flip Text -> Char -> Text
T.snoc Char
c))
Event
_ ->
Event -> EventM n (FileBrowser n) ()
forall n. Ord n => Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventCommon Event
e
handleFileBrowserEventNormal :: (Ord n) => Vty.Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventNormal :: forall n. Ord n => Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventNormal Event
e =
case Event
e of
Vty.EvKey (Vty.KChar Char
'/') [] ->
EventM n (FileBrowser n) ()
forall n. EventM n (FileBrowser n) ()
actionFileBrowserBeginSearch
Vty.EvKey Key
Vty.KEnter [] ->
EventM n (FileBrowser n) ()
forall n. EventM n (FileBrowser n) ()
actionFileBrowserSelectEnter
Vty.EvKey (Vty.KChar Char
' ') [] ->
EventM n (FileBrowser n) ()
forall n. EventM n (FileBrowser n) ()
actionFileBrowserSelectCurrent
Event
_ ->
Event -> EventM n (FileBrowser n) ()
forall n. Ord n => Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventCommon Event
e
handleFileBrowserEventCommon :: (Ord n) => Vty.Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventCommon :: forall n. Ord n => Event -> EventM n (FileBrowser n) ()
handleFileBrowserEventCommon Event
e =
case Event
e of
Vty.EvKey (Vty.KChar Char
'b') [Modifier
Vty.MCtrl] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPageUp
Vty.EvKey (Vty.KChar Char
'f') [Modifier
Vty.MCtrl] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPageDown
Vty.EvKey (Vty.KChar Char
'd') [Modifier
Vty.MCtrl] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListHalfPageDown
Vty.EvKey (Vty.KChar Char
'u') [Modifier
Vty.MCtrl] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListHalfPageUp
Vty.EvKey (Vty.KChar Char
'g') [] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListTop
Vty.EvKey (Vty.KChar Char
'G') [] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListBottom
Vty.EvKey (Vty.KChar Char
'j') [] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListNext
Vty.EvKey (Vty.KChar Char
'k') [] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPrev
Vty.EvKey (Vty.KChar Char
'n') [Modifier
Vty.MCtrl] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListNext
Vty.EvKey (Vty.KChar Char
'p') [Modifier
Vty.MCtrl] ->
EventM n (FileBrowser n) ()
forall n. Ord n => EventM n (FileBrowser n) ()
actionFileBrowserListPrev
Event
_ ->
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) ()
-> EventM n (FileBrowser n) ()
forall c.
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) c)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> EventM n (GenericList n Vector FileInfo) c
-> EventM n (FileBrowser n) c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
zoom (GenericList n Vector FileInfo
-> Focusing
(StateT (EventState n) IO) () (GenericList n Vector FileInfo))
-> FileBrowser n
-> Focusing (StateT (EventState n) IO) () (FileBrowser n)
LensLike'
(Zoomed (EventM n (GenericList n Vector FileInfo)) ())
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL (EventM n (GenericList n Vector FileInfo) ()
-> EventM n (FileBrowser n) ())
-> EventM n (GenericList n Vector FileInfo) ()
-> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$ Event -> EventM n (GenericList n Vector FileInfo) ()
forall (t :: * -> *) n e.
(Foldable t, Splittable t, Ord n) =>
Event -> EventM n (GenericList n t e) ()
handleListEvent Event
e
markSelected :: FileInfo -> EventM n (FileBrowser n) ()
markSelected :: forall n. FileInfo -> EventM n (FileBrowser n) ()
markSelected FileInfo
e = (Set String -> Identity (Set String))
-> FileBrowser n -> Identity (FileBrowser n)
forall n (f :: * -> *).
Functor f =>
(Set String -> f (Set String))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSelectedFilesL ((Set String -> Identity (Set String))
-> FileBrowser n -> Identity (FileBrowser n))
-> (Set String -> Set String) -> EventM n (FileBrowser n) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= String -> Set String -> Set String
forall a. Ord a => a -> Set a -> Set a
Set.insert (FileInfo -> String
fileInfoFilename FileInfo
e)
maybeSelectCurrentEntry :: EventM n (FileBrowser n) ()
maybeSelectCurrentEntry :: forall n. EventM n (FileBrowser n) ()
maybeSelectCurrentEntry = do
FileBrowser n
b <- EventM n (FileBrowser n) (FileBrowser n)
forall s (m :: * -> *). MonadState s m => m s
get
Maybe FileInfo
-> (FileInfo -> EventM n (FileBrowser n) ())
-> EventM n (FileBrowser n) ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (FileBrowser n -> Maybe FileInfo
forall n. FileBrowser n -> Maybe FileInfo
fileBrowserCursor FileBrowser n
b) ((FileInfo -> EventM n (FileBrowser n) ())
-> EventM n (FileBrowser n) ())
-> (FileInfo -> EventM n (FileBrowser n) ())
-> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$ \FileInfo
entry ->
if FileBrowser n -> FileInfo -> Bool
forall n. FileBrowser n -> FileInfo -> Bool
fileBrowserSelectable FileBrowser n
b FileInfo
entry
then FileInfo -> EventM n (FileBrowser n) ()
forall n. FileInfo -> EventM n (FileBrowser n) ()
markSelected FileInfo
entry
else Bool -> EventM n (FileBrowser n) () -> EventM n (FileBrowser n) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FileInfo -> Bool
selectDirectories FileInfo
entry) (EventM n (FileBrowser n) () -> EventM n (FileBrowser n) ())
-> EventM n (FileBrowser n) () -> EventM n (FileBrowser n) ()
forall a b. (a -> b) -> a -> b
$
FileBrowser n -> EventM n (FileBrowser n) ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (FileBrowser n -> EventM n (FileBrowser n) ())
-> EventM n (FileBrowser n) (FileBrowser n)
-> EventM n (FileBrowser n) ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO (FileBrowser n) -> EventM n (FileBrowser n) (FileBrowser n)
forall a. IO a -> EventM n (FileBrowser n) a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (String -> FileBrowser n -> IO (FileBrowser n)
forall n. String -> FileBrowser n -> IO (FileBrowser n)
setWorkingDirectory (FileInfo -> String
fileInfoFilePath FileInfo
entry) FileBrowser n
b)
selectCurrentEntry :: EventM n (FileBrowser n) ()
selectCurrentEntry :: forall n. EventM n (FileBrowser n) ()
selectCurrentEntry = do
FileBrowser n
b <- EventM n (FileBrowser n) (FileBrowser n)
forall s (m :: * -> *). MonadState s m => m s
get
Maybe FileInfo
-> (FileInfo -> EventM n (FileBrowser n) ())
-> EventM n (FileBrowser n) ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (FileBrowser n -> Maybe FileInfo
forall n. FileBrowser n -> Maybe FileInfo
fileBrowserCursor FileBrowser n
b) FileInfo -> EventM n (FileBrowser n) ()
forall n. FileInfo -> EventM n (FileBrowser n) ()
markSelected
renderFileBrowser :: (Show n, Ord n)
=> Bool
-> FileBrowser n
-> Widget n
renderFileBrowser :: forall n. (Show n, Ord n) => Bool -> FileBrowser n -> Widget n
renderFileBrowser Bool
foc FileBrowser n
b =
let maxFilenameLength :: Int
maxFilenameLength = GenericList n Vector Int -> Int
forall a. Ord a => GenericList n Vector a -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum (GenericList n Vector Int -> Int)
-> GenericList n Vector Int -> Int
forall a b. (a -> b) -> a -> b
$ String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> (FileInfo -> String) -> FileInfo -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileInfo -> String
fileInfoFilename (FileInfo -> Int)
-> GenericList n Vector FileInfo -> GenericList n Vector Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (FileBrowser n
bFileBrowser n
-> Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> GenericList n Vector FileInfo
forall s a. s -> Getting a s a -> a
^.Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL)
cwdHeader :: Widget n
cwdHeader = Padding -> Widget n -> Widget n
forall n. Padding -> Widget n -> Widget n
padRight Padding
Max (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
String -> Widget n
forall n. String -> Widget n
str (String -> Widget n) -> String -> Widget n
forall a b. (a -> b) -> a -> b
$ ShowS
sanitizeFilename ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ FileBrowser n -> String
forall n. FileBrowser n -> String
fileBrowserWorkingDirectory FileBrowser n
b
selInfo :: Widget n
selInfo = case GenericList n Vector FileInfo -> Maybe (Int, FileInfo)
forall (t :: * -> *) e n.
(Splittable t, Traversable t, Semigroup (t e)) =>
GenericList n t e -> Maybe (Int, e)
listSelectedElement (FileBrowser n
bFileBrowser n
-> Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> GenericList n Vector FileInfo
forall s a. s -> Getting a s a -> a
^.Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL) of
Maybe (Int, FileInfo)
Nothing -> Int -> Widget n -> Widget n
forall n. Int -> Widget n -> Widget n
vLimit Int
1 (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$ Char -> Widget n
forall n. Char -> Widget n
fill Char
' '
Just (Int
_, FileInfo
i) -> Padding -> Widget n -> Widget n
forall n. Padding -> Widget n -> Widget n
padRight Padding
Max (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$ FileInfo -> Widget n
forall {n}. FileInfo -> Widget n
selInfoFor FileInfo
i
fileTypeLabel :: Maybe FileType -> a
fileTypeLabel Maybe FileType
Nothing = a
"unknown"
fileTypeLabel (Just FileType
t) =
case FileType
t of
FileType
RegularFile -> a
"file"
FileType
BlockDevice -> a
"block device"
FileType
CharacterDevice -> a
"character device"
FileType
NamedPipe -> a
"pipe"
FileType
Directory -> a
"directory"
FileType
SymbolicLink -> a
"symbolic link"
FileType
UnixSocket -> a
"socket"
selInfoFor :: FileInfo -> Widget n
selInfoFor FileInfo
i =
let label :: Text
label = case FileInfo -> Either IOException FileStatus
fileInfoFileStatus FileInfo
i of
Left IOException
_ -> Text
"unknown"
Right FileStatus
stat ->
let maybeSize :: Text
maybeSize = if FileStatus -> Maybe FileType
fileStatusFileType FileStatus
stat Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
== FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
RegularFile
then Text
", " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int64 -> Text
prettyFileSize (FileStatus -> Int64
fileStatusSize FileStatus
stat)
else Text
""
in Maybe FileType -> Text
forall {a}. IsString a => Maybe FileType -> a
fileTypeLabel (FileStatus -> Maybe FileType
fileStatusFileType FileStatus
stat) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
maybeSize
in Text -> Widget n
forall n. Text -> Widget n
txt (Text -> Widget n) -> Text -> Widget n
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (FileInfo -> String
fileInfoSanitizedFilename FileInfo
i) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
label
maybeSearchInfo :: Widget n
maybeSearchInfo = case FileBrowser n
bFileBrowser n
-> Getting (Maybe Text) (FileBrowser n) (Maybe Text) -> Maybe Text
forall s a. s -> Getting a s a -> a
^.Getting (Maybe Text) (FileBrowser n) (Maybe Text)
forall n (f :: * -> *).
Functor f =>
(Maybe Text -> f (Maybe Text))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSearchStringL of
Maybe Text
Nothing -> Widget n
forall n. Widget n
emptyWidget
Just Text
s -> Padding -> Widget n -> Widget n
forall n. Padding -> Widget n -> Widget n
padRight Padding
Max (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
Text -> Widget n
forall n. Text -> Widget n
txt Text
"Search: " Widget n -> Widget n -> Widget n
forall n. Widget n -> Widget n -> Widget n
<+>
n -> Location -> Widget n -> Widget n
forall n. n -> Location -> Widget n -> Widget n
showCursor (FileBrowser n
bFileBrowser n -> Getting n (FileBrowser n) n -> n
forall s a. s -> Getting a s a -> a
^.Getting n (FileBrowser n) n
forall n (f :: * -> *).
Functor f =>
(n -> f n) -> FileBrowser n -> f (FileBrowser n)
fileBrowserNameL) ((Int, Int) -> Location
Location (Text -> Int
T.length Text
s, Int
0)) (Text -> Widget n
forall n. Text -> Widget n
txt Text
s)
in AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
withDefAttr AttrName
fileBrowserAttr (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
[Widget n] -> Widget n
forall n. [Widget n] -> Widget n
vBox [ AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
withDefAttr AttrName
fileBrowserCurrentDirectoryAttr Widget n
forall n. Widget n
cwdHeader
, (Bool -> FileInfo -> Widget n)
-> Bool -> GenericList n Vector FileInfo -> Widget n
forall (t :: * -> *) n e.
(Traversable t, Splittable t, Ord n, Show n) =>
(Bool -> e -> Widget n) -> Bool -> GenericList n t e -> Widget n
renderList (Bool -> Int -> Set String -> n -> Bool -> FileInfo -> Widget n
forall n.
Bool -> Int -> Set String -> n -> Bool -> FileInfo -> Widget n
renderFileInfo Bool
foc Int
maxFilenameLength (FileBrowser n
bFileBrowser n
-> Getting (Set String) (FileBrowser n) (Set String) -> Set String
forall s a. s -> Getting a s a -> a
^.Getting (Set String) (FileBrowser n) (Set String)
forall n (f :: * -> *).
Functor f =>
(Set String -> f (Set String))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserSelectedFilesL) (FileBrowser n
bFileBrowser n -> Getting n (FileBrowser n) n -> n
forall s a. s -> Getting a s a -> a
^.Getting n (FileBrowser n) n
forall n (f :: * -> *).
Functor f =>
(n -> f n) -> FileBrowser n -> f (FileBrowser n)
fileBrowserNameL))
Bool
foc (FileBrowser n
bFileBrowser n
-> Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
-> GenericList n Vector FileInfo
forall s a. s -> Getting a s a -> a
^.Getting
(GenericList n Vector FileInfo)
(FileBrowser n)
(GenericList n Vector FileInfo)
forall n (f :: * -> *).
Functor f =>
(List n FileInfo -> f (List n FileInfo))
-> FileBrowser n -> f (FileBrowser n)
fileBrowserEntriesL)
, Widget n
maybeSearchInfo
, AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
withDefAttr AttrName
fileBrowserSelectionInfoAttr Widget n
forall n. Widget n
selInfo
]
renderFileInfo :: Bool -> Int -> Set.Set String -> n -> Bool -> FileInfo -> Widget n
renderFileInfo :: forall n.
Bool -> Int -> Set String -> n -> Bool -> FileInfo -> Widget n
renderFileInfo Bool
foc Int
maxLen Set String
selFiles n
n Bool
listSel FileInfo
info =
(if Bool
foc
then (if Bool
listSel then AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
forceAttr AttrName
listSelectedFocusedAttr
else if Bool
sel then AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
forceAttr AttrName
fileBrowserSelectedAttr else Widget n -> Widget n
forall a. a -> a
id)
else (if Bool
listSel then AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
forceAttr AttrName
listSelectedAttr
else if Bool
sel then AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
forceAttr AttrName
fileBrowserSelectedAttr else Widget n -> Widget n
forall a. a -> a
id)) (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
Padding -> Widget n -> Widget n
forall n. Padding -> Widget n -> Widget n
padRight Padding
Max Widget n
body
where
sel :: Bool
sel = FileInfo -> String
fileInfoFilename FileInfo
info String -> Set String -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set String
selFiles
addAttr :: Widget n -> Widget n
addAttr = (Widget n -> Widget n)
-> (FileType -> Widget n -> Widget n)
-> Maybe FileType
-> Widget n
-> Widget n
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Widget n -> Widget n
forall a. a -> a
id (AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
withDefAttr (AttrName -> Widget n -> Widget n)
-> (FileType -> AttrName) -> FileType -> Widget n -> Widget n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileType -> AttrName
attrForFileType) (FileInfo -> Maybe FileType
fileInfoFileType FileInfo
info)
body :: Widget n
body = Widget n -> Widget n
forall {n}. Widget n -> Widget n
addAttr (Int -> Widget n -> Widget n
forall n. Int -> Widget n -> Widget n
hLimit (Int
maxLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
Padding -> Widget n -> Widget n
forall n. Padding -> Widget n -> Widget n
padRight Padding
Max (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
(if Bool
foc Bool -> Bool -> Bool
&& Bool
listSel then n -> Location -> Widget n -> Widget n
forall n. n -> Location -> Widget n -> Widget n
putCursor n
n ((Int, Int) -> Location
Location (Int
0,Int
0)) else Widget n -> Widget n
forall a. a -> a
id) (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
String -> Widget n
forall n. String -> Widget n
str (String -> Widget n) -> String -> Widget n
forall a b. (a -> b) -> a -> b
$ FileInfo -> String
fileInfoSanitizedFilename FileInfo
info String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
suffix)
suffix :: String
suffix = (if FileInfo -> Maybe FileType
fileInfoFileType FileInfo
info Maybe FileType -> Maybe FileType -> Bool
forall a. Eq a => a -> a -> Bool
== FileType -> Maybe FileType
forall a. a -> Maybe a
Just FileType
Directory then String
"/" else String
"") String -> ShowS
forall a. Semigroup a => a -> a -> a
<>
(if Bool
sel then String
"*" else String
"")
sanitizeFilename :: String -> String
sanitizeFilename :: ShowS
sanitizeFilename = (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Char -> Char
toPrint
where
toPrint :: Char -> Char
toPrint Char
c | Char -> Bool
isPrint Char
c = Char
c
| Bool
otherwise = Char
'?'
attrForFileType :: FileType -> AttrName
attrForFileType :: FileType -> AttrName
attrForFileType FileType
RegularFile = AttrName
fileBrowserRegularFileAttr
attrForFileType FileType
BlockDevice = AttrName
fileBrowserBlockDeviceAttr
attrForFileType FileType
CharacterDevice = AttrName
fileBrowserCharacterDeviceAttr
attrForFileType FileType
NamedPipe = AttrName
fileBrowserNamedPipeAttr
attrForFileType FileType
Directory = AttrName
fileBrowserDirectoryAttr
attrForFileType FileType
SymbolicLink = AttrName
fileBrowserSymbolicLinkAttr
attrForFileType FileType
UnixSocket = AttrName
fileBrowserUnixSocketAttr
fileBrowserAttr :: AttrName
fileBrowserAttr :: AttrName
fileBrowserAttr = String -> AttrName
attrName String
"fileBrowser"
fileBrowserCurrentDirectoryAttr :: AttrName
fileBrowserCurrentDirectoryAttr :: AttrName
fileBrowserCurrentDirectoryAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"currentDirectory"
fileBrowserSelectionInfoAttr :: AttrName
fileBrowserSelectionInfoAttr :: AttrName
fileBrowserSelectionInfoAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"selectionInfo"
fileBrowserDirectoryAttr :: AttrName
fileBrowserDirectoryAttr :: AttrName
fileBrowserDirectoryAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"directory"
fileBrowserBlockDeviceAttr :: AttrName
fileBrowserBlockDeviceAttr :: AttrName
fileBrowserBlockDeviceAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"block"
fileBrowserRegularFileAttr :: AttrName
fileBrowserRegularFileAttr :: AttrName
fileBrowserRegularFileAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"regular"
fileBrowserCharacterDeviceAttr :: AttrName
fileBrowserCharacterDeviceAttr :: AttrName
fileBrowserCharacterDeviceAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"char"
fileBrowserNamedPipeAttr :: AttrName
fileBrowserNamedPipeAttr :: AttrName
fileBrowserNamedPipeAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"pipe"
fileBrowserSymbolicLinkAttr :: AttrName
fileBrowserSymbolicLinkAttr :: AttrName
fileBrowserSymbolicLinkAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"symlink"
fileBrowserUnixSocketAttr :: AttrName
fileBrowserUnixSocketAttr :: AttrName
fileBrowserUnixSocketAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"unixSocket"
fileBrowserSelectedAttr :: AttrName
fileBrowserSelectedAttr :: AttrName
fileBrowserSelectedAttr = AttrName
fileBrowserAttr AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"selected"
fileTypeMatch :: [FileType] -> FileInfo -> Bool
fileTypeMatch :: [FileType] -> FileInfo -> Bool
fileTypeMatch [FileType]
tys FileInfo
i = Bool -> (FileType -> Bool) -> Maybe FileType -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (FileType -> [FileType] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FileType]
tys) (Maybe FileType -> Bool) -> Maybe FileType -> Bool
forall a b. (a -> b) -> a -> b
$ FileInfo -> Maybe FileType
fileInfoFileType FileInfo
i
fileExtensionMatch :: String -> FileInfo -> Bool
fileExtensionMatch :: String -> FileInfo -> Bool
fileExtensionMatch String
ext FileInfo
i = case FileInfo -> Maybe FileType
fileInfoFileType FileInfo
i of
Just FileType
Directory -> Bool
True
Just FileType
RegularFile -> (Char
'.' Char -> ShowS
forall a. a -> [a] -> [a]
: (Char -> Char
toLower (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String
ext)) String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` (Char -> Char
toLower (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FileInfo -> String
fileInfoFilename FileInfo
i)
Just FileType
SymbolicLink -> case FileInfo -> Maybe FileType
fileInfoLinkTargetType FileInfo
i of
Just FileType
Directory -> Bool
True
Maybe FileType
_ -> Bool
False
Maybe FileType
_ -> Bool
False