Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
This module provides a file browser widget that allows users to
navigate directory trees, search for files and directories, and
select entries of interest. For a complete working demonstration of
this module, see programs/FileBrowserDemo.hs
.
To use this module:
- Embed a
FileBrowser
in your application state. - Dispatch events to it in your event handler with
handleFileBrowserEvent
. - Get the entry under the browser's cursor with
fileBrowserCursor
and get the entries selected by the user withEnter
orSpace
usingfileBrowserSelection
. - Inspect
fileBrowserException
to determine whether the file browser encountered an error when reading a directory insetWorkingDirectory
or when changing directories in the event handler.
File browsers have a built-in user-configurable function to limit the
entries displayed that defaults to showing all files. For example,
an application might want to limit the browser to just directories
and XML files. That is accomplished by setting the filter with
setFileBrowserEntryFilter
and some examples are provided in this
module: fileTypeMatch
and fileExtensionMatch
.
File browsers are styled using the provided collection of attribute
names, so add those to your attribute map to get the appearance you
want. File browsers also make use of a List
internally, so the
List
attributes will affect how the list appears.
File browsers catch IOException
s when changing directories. If a
call to setWorkingDirectory
triggers an IOException
while reading
the working directory, the resulting IOException
is stored in the
file browser and is accessible with fileBrowserException
. The
setWorkingDirectory
function clears the exception field if the
working directory is read successfully. The caller is responsible for
deciding when and whether to display the exception to the user. In
the event that an IOException
is raised as described here, the file
browser will always present ..
as a navigation option to allow the
user to continue navigating up the directory tree. It does this even
if the current or parent directory does not exist or cannot be read,
so it is always safe to present a file browser for any working
directory. Bear in mind that the ..
entry is always subjected to
filtering and searching.
Synopsis
- data FileBrowser n
- data FileInfo = FileInfo {}
- data FileStatus = FileStatus {}
- data FileType
- newFileBrowser :: (FileInfo -> Bool) -> n -> Maybe FilePath -> IO (FileBrowser n)
- selectNonDirectories :: FileInfo -> Bool
- selectDirectories :: FileInfo -> Bool
- setWorkingDirectory :: FilePath -> FileBrowser n -> IO (FileBrowser n)
- getWorkingDirectory :: FileBrowser n -> FilePath
- updateFileBrowserSearch :: (Maybe Text -> Maybe Text) -> FileBrowser n -> FileBrowser n
- setFileBrowserEntryFilter :: Maybe (FileInfo -> Bool) -> FileBrowser n -> FileBrowser n
- actionFileBrowserBeginSearch :: EventM n (FileBrowser n) ()
- actionFileBrowserSelectEnter :: EventM n (FileBrowser n) ()
- actionFileBrowserSelectCurrent :: EventM n (FileBrowser n) ()
- actionFileBrowserListPageUp :: Ord n => EventM n (FileBrowser n) ()
- actionFileBrowserListPageDown :: Ord n => EventM n (FileBrowser n) ()
- actionFileBrowserListHalfPageUp :: Ord n => EventM n (FileBrowser n) ()
- actionFileBrowserListHalfPageDown :: Ord n => EventM n (FileBrowser n) ()
- actionFileBrowserListTop :: Ord n => EventM n (FileBrowser n) ()
- actionFileBrowserListBottom :: Ord n => EventM n (FileBrowser n) ()
- actionFileBrowserListNext :: Ord n => EventM n (FileBrowser n) ()
- actionFileBrowserListPrev :: Ord n => EventM n (FileBrowser n) ()
- handleFileBrowserEvent :: Ord n => Event -> EventM n (FileBrowser n) ()
- maybeSelectCurrentEntry :: EventM n (FileBrowser n) ()
- renderFileBrowser :: (Show n, Ord n) => Bool -> FileBrowser n -> Widget n
- fileBrowserCursor :: FileBrowser n -> Maybe FileInfo
- fileBrowserIsSearching :: FileBrowser n -> Bool
- fileBrowserSelection :: FileBrowser n -> [FileInfo]
- fileBrowserException :: FileBrowser n -> Maybe IOException
- fileBrowserSelectable :: FileBrowser n -> FileInfo -> Bool
- fileInfoFileType :: FileInfo -> Maybe FileType
- fileBrowserAttr :: AttrName
- fileBrowserCurrentDirectoryAttr :: AttrName
- fileBrowserSelectionInfoAttr :: AttrName
- fileBrowserSelectedAttr :: AttrName
- fileBrowserDirectoryAttr :: AttrName
- fileBrowserBlockDeviceAttr :: AttrName
- fileBrowserRegularFileAttr :: AttrName
- fileBrowserCharacterDeviceAttr :: AttrName
- fileBrowserNamedPipeAttr :: AttrName
- fileBrowserSymbolicLinkAttr :: AttrName
- fileBrowserUnixSocketAttr :: AttrName
- fileTypeMatch :: [FileType] -> FileInfo -> Bool
- fileExtensionMatch :: String -> FileInfo -> Bool
- fileBrowserSelectableL :: forall n. Lens' (FileBrowser n) (FileInfo -> Bool)
- fileInfoFilenameL :: Lens' FileInfo String
- fileInfoSanitizedFilenameL :: Lens' FileInfo String
- fileInfoFilePathL :: Lens' FileInfo FilePath
- fileInfoFileStatusL :: Lens' FileInfo (Either IOException FileStatus)
- fileInfoLinkTargetTypeL :: Lens' FileInfo (Maybe FileType)
- fileStatusSizeL :: Lens' FileStatus Int64
- fileStatusFileTypeL :: Lens' FileStatus (Maybe FileType)
- fileBrowserEntryFilterG :: forall n. SimpleGetter (FileBrowser n) (Maybe (FileInfo -> Bool))
- fileBrowserWorkingDirectoryG :: forall n. SimpleGetter (FileBrowser n) FilePath
- fileBrowserEntriesG :: forall n. SimpleGetter (FileBrowser n) (List n FileInfo)
- fileBrowserLatestResultsG :: forall n. SimpleGetter (FileBrowser n) [FileInfo]
- fileBrowserSelectedFilesG :: forall n. SimpleGetter (FileBrowser n) (Set String)
- fileBrowserNameG :: forall n. SimpleGetter (FileBrowser n) n
- fileBrowserSearchStringG :: forall n. SimpleGetter (FileBrowser n) (Maybe Text)
- fileBrowserExceptionG :: forall n. SimpleGetter (FileBrowser n) (Maybe IOException)
- fileBrowserSelectableG :: forall n. SimpleGetter (FileBrowser n) (FileInfo -> Bool)
- prettyFileSize :: Int64 -> Text
- entriesForDirectory :: FilePath -> IO [FileInfo]
- getFileInfo :: String -> FilePath -> IO FileInfo
Types
data FileBrowser n Source #
A file browser's state. Embed this in your application state and
transform it with handleFileBrowserEvent
and the functions included
in this module.
Instances
Named (FileBrowser n) n Source # | |
Defined in Brick.Widgets.FileBrowser getName :: FileBrowser n -> n Source # |
Information about a file entry in the browser.
FileInfo | |
|
Instances
data FileStatus Source #
File status information.
FileStatus | |
|
Instances
Show FileStatus Source # | |
Defined in Brick.Widgets.FileBrowser showsPrec :: Int -> FileStatus -> ShowS # show :: FileStatus -> String # showList :: [FileStatus] -> ShowS # | |
Eq FileStatus Source # | |
Defined in Brick.Widgets.FileBrowser (==) :: FileStatus -> FileStatus -> Bool # (/=) :: FileStatus -> FileStatus -> Bool # |
The type of file entries in the browser.
RegularFile | A regular disk file. |
BlockDevice | A block device. |
CharacterDevice | A character device. |
NamedPipe | A named pipe. |
Directory | A directory. |
SymbolicLink | A symbolic link. |
UnixSocket | A Unix socket. |
Making a new file browser
:: (FileInfo -> Bool) | The function used to determine what kinds of entries
can be selected (see |
-> n | The resource name associated with the browser's entry listing. |
-> Maybe FilePath | The initial working directory that the browser displays. If not provided, this defaults to the executable's current working directory. |
-> IO (FileBrowser n) |
Make a new file browser state. The provided resource name will be
used to render the List
viewport of the browser.
By default, the browser will show all files and directories
in its working directory. To change that behavior, see
setFileBrowserEntryFilter
.
selectNonDirectories :: FileInfo -> Bool Source #
A file entry selector that permits selection of all file entries
except directories. Use this if you want users to be able to navigate
directories in the browser. If you want users to be able to select
only directories, use selectDirectories
.
selectDirectories :: FileInfo -> Bool Source #
A file entry selector that permits selection of directories only. This prevents directory navigation and only supports directory selection.
Manipulating a file browser's state
setWorkingDirectory :: FilePath -> FileBrowser n -> IO (FileBrowser n) Source #
Set the working directory of the file browser. This scans the new directory and repopulates the browser while maintaining any active search string and/or entry filtering.
If the directory scan raises an IOException
, the exception is
stored in the browser and is accessible with fileBrowserException
. If
no exception is raised, the exception field is cleared. Regardless of
whether an exception is raised, ..
is always presented as a valid
option in the browser.
getWorkingDirectory :: FileBrowser n -> FilePath Source #
Get the working directory of the file browser.
updateFileBrowserSearch Source #
:: (Maybe Text -> Maybe Text) | The search transformation. |
-> FileBrowser n | The browser to modify. |
-> FileBrowser n |
Modify the file browser's active search string. This causes the browser's displayed entries to change to those in its current directory that match the search string, if any. If a search string is provided, it is matched case-insensitively anywhere in file or directory names.
setFileBrowserEntryFilter :: Maybe (FileInfo -> Bool) -> FileBrowser n -> FileBrowser n Source #
Set the filtering function used to determine which entries in
the browser's current directory appear in the browser. Nothing
indicates no filtering, meaning all entries will be shown. Just
indicates a function that should return True
for entries that
should be permitted to appear.
Note that this applies the filter after setting it by updating the
listed entries to reflect the result of the filter. That is unlike
setting the filter with the fileBrowserEntryFilterL
lens directly,
which just sets the filter but does not (and cannot) update the
listed entries.
Actions
actionFileBrowserBeginSearch :: EventM n (FileBrowser n) () Source #
Handle a Vty input event. Note that event handling can
cause a directory change so the caller should be aware that
fileBrowserException
may need to be checked after handling an
event in case an exception was triggered while scanning the working
directory.
Events handled regardless of mode:
Ctrl-b
:actionFileBrowserListPageUp
Ctrl-f
:actionFileBrowserListPageDown
Ctrl-d
:actionFileBrowserListHalfPageDown
Ctrl-u
:actionFileBrowserListHalfPageUp
Ctrl-n
:actionFileBrowserListNext
Ctrl-p
:actionFileBrowserListPrev
Events handled only in normal mode:
/
:actionFileBrowserBeginSearch
Enter
:actionFileBrowserSelectEnter
Space
:actionFileBrowserSelectCurrent
g
:actionFileBrowserListTop
G
:actionFileBrowserListBottom
j
:actionFileBrowserListNext
k
:actionFileBrowserListPrev
Events handled only in search mode:
Esc
,Ctrl-C
: cancel search mode- Text input: update search string
actionFileBrowserSelectEnter :: EventM n (FileBrowser n) () Source #
actionFileBrowserSelectCurrent :: EventM n (FileBrowser n) () Source #
actionFileBrowserListPageUp :: Ord n => EventM n (FileBrowser n) () Source #
actionFileBrowserListPageDown :: Ord n => EventM n (FileBrowser n) () Source #
actionFileBrowserListHalfPageUp :: Ord n => EventM n (FileBrowser n) () Source #
actionFileBrowserListHalfPageDown :: Ord n => EventM n (FileBrowser n) () Source #
actionFileBrowserListTop :: Ord n => EventM n (FileBrowser n) () Source #
actionFileBrowserListBottom :: Ord n => EventM n (FileBrowser n) () Source #
actionFileBrowserListNext :: Ord n => EventM n (FileBrowser n) () Source #
actionFileBrowserListPrev :: Ord n => EventM n (FileBrowser n) () Source #
Handling events
handleFileBrowserEvent :: Ord n => Event -> EventM n (FileBrowser n) () Source #
maybeSelectCurrentEntry :: EventM n (FileBrowser n) () Source #
If the browser's current entry is selectable according to
fileBrowserSelectable
, add it to the selection set and return.
If not, and if the entry is a directory or a symlink targeting a
directory, set the browser's current path to the selected directory.
Otherwise, return the browser state unchanged.
Rendering
:: (Show n, Ord n) | |
=> Bool | Whether the file browser has input focus. |
-> FileBrowser n | The browser to render. |
-> Widget n |
Render a file browser. This renders a list of entries in the working directory, a cursor to select from among the entries, a header displaying the working directory, and a footer displaying information about the selected entry.
Note that if the most recent file browser operation produced an
exception in fileBrowserException
, that exception is not rendered
by this function. That exception needs to be rendered (if at all) by
the calling application.
The file browser is greedy in both dimensions.
Getting information
fileBrowserCursor :: FileBrowser n -> Maybe FileInfo Source #
Get the file information for the file under the cursor, if any.
fileBrowserIsSearching :: FileBrowser n -> Bool Source #
Returns whether the file browser is in search mode, i.e., the mode in which user input affects the browser's active search string and displayed entries. This is used to aid in event dispatching in the calling program.
fileBrowserSelection :: FileBrowser n -> [FileInfo] Source #
Get the entries chosen by the user, if any. Entries are chosen by
an Enter
or Space
keypress; if you want the entry under the
cursor, use fileBrowserCursor
.
fileBrowserException :: FileBrowser n -> Maybe IOException Source #
The exception status of the latest directory
change. If Nothing
, the latest directory change
was successful and all entries were read. Otherwise,
this contains the exception raised by the latest
directory change in case the calling application
needs to inspect or present the error to the user.
fileBrowserSelectable :: FileBrowser n -> FileInfo -> Bool Source #
The function that determines what kinds of entries
are selectable with in the event handler. Note that
if this returns True
for an entry, an Enter
or
Space
keypress selects that entry rather than doing
anything else; directory changes can only occur if
this returns False
for directories.
Note that this is a record field so it can be used to change the selection function.
fileInfoFileType :: FileInfo -> Maybe FileType Source #
Get the file type for this file info entry. If the file type could
not be obtained due to an IOException
, return Nothing
.
Attributes
fileBrowserAttr :: AttrName Source #
The base attribute for all file browser attributes.
fileBrowserCurrentDirectoryAttr :: AttrName Source #
The attribute used for the current directory displayed at the top of the browser.
fileBrowserSelectionInfoAttr :: AttrName Source #
The attribute used for the entry information displayed at the bottom of the browser.
fileBrowserSelectedAttr :: AttrName Source #
The attribute used for selected entries in the file browser.
fileBrowserDirectoryAttr :: AttrName Source #
The attribute used to render directory entries.
fileBrowserBlockDeviceAttr :: AttrName Source #
The attribute used to render block device entries.
fileBrowserRegularFileAttr :: AttrName Source #
The attribute used to render regular file entries.
fileBrowserCharacterDeviceAttr :: AttrName Source #
The attribute used to render character device entries.
fileBrowserNamedPipeAttr :: AttrName Source #
The attribute used to render named pipe entries.
fileBrowserSymbolicLinkAttr :: AttrName Source #
The attribute used to render symbolic link entries.
fileBrowserUnixSocketAttr :: AttrName Source #
The attribute used to render Unix socket entries.
Example browser entry filters
fileTypeMatch :: [FileType] -> FileInfo -> Bool Source #
A file type filter for use with setFileBrowserEntryFilter
. This
filter permits entries whose file types are in the specified list.
fileExtensionMatch :: String -> FileInfo -> Bool Source #
A filter that matches any directory regardless of name, or any
regular file with the specified extension. For example, an extension
argument of "xml"
would match regular files test.xml
and
TEST.XML
and it will match directories regardless of name.
This matcher also matches symlinks if and only if their targets are directories. This is intended to make it possible to use this matcher to find files with certain extensions, but also support directory traversal via symlinks.
Lenses
fileBrowserSelectableL :: forall n. Lens' (FileBrowser n) (FileInfo -> Bool) Source #
Getters
fileBrowserEntryFilterG :: forall n. SimpleGetter (FileBrowser n) (Maybe (FileInfo -> Bool)) Source #
fileBrowserWorkingDirectoryG :: forall n. SimpleGetter (FileBrowser n) FilePath Source #
fileBrowserEntriesG :: forall n. SimpleGetter (FileBrowser n) (List n FileInfo) Source #
fileBrowserLatestResultsG :: forall n. SimpleGetter (FileBrowser n) [FileInfo] Source #
fileBrowserSelectedFilesG :: forall n. SimpleGetter (FileBrowser n) (Set String) Source #
fileBrowserNameG :: forall n. SimpleGetter (FileBrowser n) n Source #
fileBrowserSearchStringG :: forall n. SimpleGetter (FileBrowser n) (Maybe Text) Source #
fileBrowserExceptionG :: forall n. SimpleGetter (FileBrowser n) (Maybe IOException) Source #
fileBrowserSelectableG :: forall n. SimpleGetter (FileBrowser n) (FileInfo -> Bool) Source #
Miscellaneous
Generate a textual abbreviation of a file size, e.g. "10.2M" or "12 bytes".
Utilities
entriesForDirectory :: FilePath -> IO [FileInfo] Source #
Build a list of file info entries for the specified directory. This
function does not catch any exceptions raised by calling
makeAbsolute
or listDirectory
, but it does catch exceptions on
a per-file basis. Any exceptions caught when inspecting individual
files are stored in the fileInfoFileStatus
field of each
FileInfo
.
The entries returned are all entries in the specified directory
except for .
and ..
. Directories are always given first. Entries
are sorted in case-insensitive lexicographic order.
This function is exported for those who want to implement their own file browser using the types in this module.
:: String | The name of the file to inspect. This filename is only
used to set the |
-> FilePath | The actual full path to the file or directory to inspect. |
-> IO FileInfo |
Build a FileInfo
for the specified file and path. If an
IOException
is raised while attempting to get the file information,
the fileInfoFileStatus
field is populated with the exception.
Otherwise it is populated with the FileStatus
for the file.