brick-2.1.1: A declarative terminal user interface library

Safe Haskell | Safe-Inferred
Language | Haskell2010

Brick.Widgets.FileBrowser

Contents

- Types
- Making a new file browser
- Manipulating a file browser's state
- Actions
- Handling events
- Rendering
- Getting information
- Attributes
- Example browser entry filters
- Lenses
- Getters
- Miscellaneous
- Utilities

Description

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 with `Enter` or `Space` using `fileBrowserSelection`.
- Inspect `fileBrowserException` to determine whether the file browser encountered an error when reading a directory in `setWorkingDirectory` 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 {
  - fileInfoFilename :: String
  - fileInfoSanitizedFilename :: String
  - fileInfoFilePath :: FilePath
  - fileInfoFileStatus :: Either IOException FileStatus
  - fileInfoLinkTargetType :: Maybe FileType
  }
- data FileStatus = FileStatus {
  - fileStatusSize :: Int64
  - fileStatusFileType :: Maybe FileType
  }
- data FileType
  - = RegularFile
  - | BlockDevice
  - | CharacterDevice
  - | NamedPipe
  - | Directory
  - | SymbolicLink
  - | UnixSocket
- 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

Instances details

Named (FileBrowser n) n Source # |
Instance details Defined in Brick.Widgets.FileBrowser Methods getName :: FileBrowser n -> n Source #

data FileInfo Source #

Information about a file entry in the browser.

Constructors

FileInfo |

Fields

- fileInfoFilename :: String

  The filename of this entry, without its path. This is not for display purposes; for that, use `fileInfoSanitizedFilename`.

- fileInfoSanitizedFilename :: String

  The filename of this entry with out its path, sanitized of non-printable characters (replaced with `?`). This is for display purposes only.

- fileInfoFilePath :: FilePath

  The full path to this entry's file.

- fileInfoFileStatus :: Either IOException FileStatus

  The file status if it could be obtained, or the exception that was caught when attempting to read the file's status.

- fileInfoLinkTargetType :: Maybe FileType

  If this entry is a symlink, this indicates the type of file the symlink points to, if it could be obtained.

#### Instances

Instances details

Show FileInfo Source # |
Instance details Defined in Brick.Widgets.FileBrowser Methods showsPrec :: Int -> FileInfo -> ShowS Source # show :: FileInfo -> String Source # showList :: [FileInfo] -> ShowS Source #
Eq FileInfo Source # |
Instance details Defined in Brick.Widgets.FileBrowser Methods (==) :: FileInfo -> FileInfo -> Bool Source # (/=) :: FileInfo -> FileInfo -> Bool Source #

data FileStatus Source #

File status information.

Constructors

FileStatus |

Fields

- fileStatusSize :: Int64

  The size, in bytes, of this entry's file.

- fileStatusFileType :: Maybe FileType

  The type of this entry's file, if it could be determined.

#### Instances

Instances details

Show FileStatus Source # |
Instance details Defined in Brick.Widgets.FileBrowser Methods showsPrec :: Int -> FileStatus -> ShowS Source # show :: FileStatus -> String Source # showList :: [FileStatus] -> ShowS Source #
Eq FileStatus Source # |
Instance details Defined in Brick.Widgets.FileBrowser Methods (==) :: FileStatus -> FileStatus -> Bool Source # (/=) :: FileStatus -> FileStatus -> Bool Source #

data FileType Source #

The type of file entries in the browser.

Constructors

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.

#### Instances

Instances details

Read FileType Source # |
Instance details Defined in Brick.Widgets.FileBrowser Methods readsPrec :: Int -> ReadS FileType Source # readList :: ReadS [FileType] Source # readPrec :: ReadPrec FileType Source # readListPrec :: ReadPrec [FileType] Source #
Show FileType Source # |
Instance details Defined in Brick.Widgets.FileBrowser Methods showsPrec :: Int -> FileType -> ShowS Source # show :: FileType -> String Source # showList :: [FileType] -> ShowS Source #
Eq FileType Source # |
Instance details Defined in Brick.Widgets.FileBrowser Methods (==) :: FileType -> FileType -> Bool Source # (/=) :: FileType -> FileType -> Bool Source #

# Making a new file browser

newFileBrowser Source #

Arguments

:: (FileInfo -> Bool) | The function used to determine what kinds of entries can be selected (see `handleFileBrowserEvent`). A good default is `selectNonDirectories`. This can be changed at 'any time with `fileBrowserSelectable` or its 'corresponding lens.
-> 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 #

Arguments

:: (Maybe Text -> Maybe Text) | The search transformation. `Nothing` indicates that search mode should be off; `Just` indicates that it should be on and that the provided search string should be used.
-> 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

renderFileBrowser Source #

Arguments

:: (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 #

fileInfoFilenameL :: Lens' FileInfo String Source #

fileInfoSanitizedFilenameL :: Lens' FileInfo String Source #

fileInfoFilePathL :: Lens' FileInfo FilePath Source #

fileInfoFileStatusL :: Lens' FileInfo (Either IOException FileStatus) Source #

fileInfoLinkTargetTypeL :: Lens' FileInfo (Maybe FileType) Source #

fileStatusSizeL :: Lens' FileStatus Int64 Source #

fileStatusFileTypeL :: Lens' FileStatus (Maybe FileType) 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

prettyFileSize Source #

Arguments

:: Int64 | A file size in bytes.
-> Text |

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.

getFileInfo Source #

Arguments

:: String | The name of the file to inspect. This filename is only used to set the `fileInfoFilename` and sanitized filename fields; the actual file to be inspected is referred to by the second argument. This is decomposed so that `FileInfo`s can be used to represent information about entries like `..`, whose display names differ from their physical paths.
-> 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.