hledger-lib-1.52.1: A library providing the core functionality of hledger

Safe Haskell | None
Language | GHC2021

Hledger.Utils.IO

Contents

- Pretty showing/printing
- Errors
- Time
- Files
- Command line parsing
- Terminal size
- Pager output
- ANSI colour/styles
  - hledger-specific
  - Generic

Description

General and hledger-specific input/output-related helpers for pretty-printing haskell values, error reporting, time, files, command line parsing, terminals, pager output, ANSI colour/styles, etc.

Synopsis

- pshow :: Show a => a -> String
- pshow' :: Show a => a -> String
- pprint :: Show a => a -> IO ()
- pprint' :: Show a => a -> IO ()
- error' :: String -> a
- usageError :: String -> a
- warn :: String -> a -> a
- warnIO :: MonadIO m => String -> m ()
- ansiFormatError :: String -> String
- ansiFormatWarning :: String -> String
- printError :: String -> IO ()
- exitWithErrorMessage :: String -> IO ()
- handleExit :: IO () -> IO ()
- getCurrentLocalTime :: IO LocalTime
- getCurrentZonedTime :: IO ZonedTime
- getHomeSafe :: IO (Maybe FilePath)
- embedFileRelative :: FilePath -> Q Exp
- expandHomePath :: FilePath -> IO FilePath
- expandPath :: FilePath -> FilePath -> IO FilePath
- expandGlob :: FilePath -> FilePath -> IO [FilePath]
- expandPathOrGlob :: FilePath -> FilePath -> IO FilePath
- sortByModTime :: [FilePath] -> IO [FilePath]
- openFileOrStdin :: String -> IO Handle
- readFileOrStdinPortably :: String -> IO Text
- readFileOrStdinPortably' :: Maybe DynEncoding -> String -> IO Text
- readFileStrictly :: FilePath -> IO Text
- readFilePortably :: FilePath -> IO Text
- hGetContentsPortably :: Maybe DynEncoding -> Handle -> IO Text
- textToHandle :: Text -> IO Handle
- progArgs :: [String]
- getFlag :: [String] -> IO Bool
- getOpt :: [String] -> IO (Maybe String)
- parseYN :: String -> Either String Bool
- parseYNA :: String -> Either String YNA
- data YNA
  - = Yes
  - | No
  - | Auto
- getTerminalHeightWidth :: IO (Maybe (Int, Int))
- getTerminalHeight :: IO (Maybe Int)
- getTerminalWidth :: IO (Maybe Int)
- findPager :: IO (Maybe String)
- runPager :: String -> IO ()
- lessVarValue :: Maybe String -> Maybe String -> Bool -> String
- lessIsWorking :: Maybe [(String, String)] -> IO Bool
- colorOption :: IO YNA
- useColorOnStdout :: IO Bool
- useColorOnStderr :: IO Bool
- useColorOnStdoutUnsafe :: Bool
- useColorOnStderrUnsafe :: Bool
- bold' :: String -> String
- faint' :: String -> String
- black' :: String -> String
- red' :: String -> String
- green' :: String -> String
- yellow' :: String -> String
- blue' :: String -> String
- magenta' :: String -> String
- cyan' :: String -> String
- white' :: String -> String
- brightBlack' :: String -> String
- brightRed' :: String -> String
- brightGreen' :: String -> String
- brightYellow' :: String -> String
- brightBlue' :: String -> String
- brightMagenta' :: String -> String
- brightCyan' :: String -> String
- brightWhite' :: String -> String
- rgb' :: Float -> Float -> Float -> String -> String
- sgrresetall :: String
- color :: ColorIntensity -> Color -> String -> String
- bgColor :: ColorIntensity -> Color -> String -> String
- colorB :: ColorIntensity -> Color -> WideBuilder -> WideBuilder
- bgColorB :: ColorIntensity -> Color -> WideBuilder -> WideBuilder
- terminalIsLight :: Maybe Bool
- terminalLightness :: Maybe Float
- terminalFgColor :: Maybe (RGB Float)
- terminalBgColor :: Maybe (RGB Float)

# Pretty showing/printing

pshow :: Show a => a -> String Source #

Pretty show. An easier alias for pretty-simple's pShow. This will probably show in colour if useColorOnStderrUnsafe is true.

pshow' :: Show a => a -> String Source #

Monochrome version of pshow. This will never show in colour.

pprint :: Show a => a -> IO () Source #

Pretty print a showable value. An easier alias for pretty-simple's pPrint. This will print in colour if useColorOnStderrUnsafe is true.

pprint' :: Show a => a -> IO () Source #

Monochrome version of pprint. This will never print in colour.

# Errors

error' :: String -> a Source #

Call errorWithoutStackTrace, prepending a "Error:" label.

usageError :: String -> a Source #

Like error', but add a hint about using -h.

warn :: String -> a -> a Source #

Show a warning message on stderr before returning the given value. Like trace, but prepends a "Warning:" label, and does some ANSI styling of the first line when allowed (using unsafe IO). Currently we use this very sparingly in hledger; we prefer to either quietly work, or loudly raise an error. Varying output can make scripting harder. But on stderr, it shouldn't cause much hassle.

warnIO :: MonadIO m => String -> m () Source #

Like warn, but take extra care to sequence properly in IO.

ansiFormatError :: String -> String Source #

Apply standard ANSI SGR formatting (red, bold) suitable for console error text.

ansiFormatWarning :: String -> String Source #

Apply standard ANSI SGR formatting (yellow, bold) suitable for console warning text.

printError :: String -> IO () Source #

Print an error message to stderr, with a consistent "programname: " prefix, and applying ANSI styling (bold bright red) to the first line if that is supported and allowed.

exitWithErrorMessage :: String -> IO () Source #

Print an error message with printError, then exit the program with a non-zero exit code.

handleExit :: IO () -> IO () Source #

This wraps a program's main routine so as to display more consistent, useful, and GHC-version-independent error output when the program exits because of certain common exceptions. It

1. disables SIGPIPE errors, which are usually harmless, caused when our output is truncated in a piped command.
2. catches these common exceptions:

- UnicodeException, caused eg by text decoding errors in pure code
- IOException, caused by IO errors, including text decoding errors during IO
- ErrorCall - `error` / `errorWithoutStackTrace` calls

1. compensates for GHC output bugs:

- removes the trailing newlines added by some GHC 9.10.* versions
- removes "uncaught exception" output added by some GHC 9.12.* versions
- ensures a consistent "PROGNAME: " prefix

1. applies bold bright red ANSI styling to the first line of error output, if that is supported and allowed
2. for unicode exceptions and I/O exceptions which look like they were unicode-related, it adds a message (in english) explaining the problem and what to do.

Some exceptions this does not catch are ExitCode (exitSuccessexitFailureexitWith) and UserInterrupt (control-C).

# Time

getCurrentLocalTime :: IO LocalTime Source #

getCurrentZonedTime :: IO ZonedTime Source #

# Files

getHomeSafe :: IO (Maybe FilePath) Source #

Like getHomeDirectory, but in case of IO error (home directory not found, not understood, etc.), returns "".

embedFileRelative :: FilePath -> Q Exp Source #

Like embedFile, but takes a path relative to the package directory.

expandHomePath :: FilePath -> IO FilePath Source #

Expand a single tilde (representing home directory) at the start of a file path. ~username is not supported. This can raise an IO error.

expandPath :: FilePath -> FilePath -> IO FilePath Source #

Given a current directory, convert a possibly relative, possibly tilde-prefixed file path to an absolute one. ~username is not supported. If the file path is "-", it is left as-is. This can an raise an IO error.

expandGlob :: FilePath -> FilePath -> IO [FilePath] Source #

Like `expandPath`, but treats the expanded path as a glob, and returns zero or more matched absolute file paths, alphabetically sorted. Can raise an error. For a more elaborate glob expander, see `findMatchedFiles` (used by the include directive).

expandPathOrGlob :: FilePath -> FilePath -> IO FilePath Source #

Like expandPath, but if the path contains glob metacharacters (* ? [ {), treats it as a glob pattern and expands it, returning the first match. Raises an error if the glob pattern matches no files. If the path contains no glob metacharacters, just expands ~ and returns the path, even if the file doesn't exist yet. This is useful for options like -f and LEDGER_FILE that should: - accept non-existent files (for commands like add/import that create them) - expand glob patterns and error if they don't match anything

sortByModTime :: [FilePath] -> IO [FilePath] Source #

Given a list of existing file paths, sort them by modification time (from oldest to newest).

openFileOrStdin :: String -> IO Handle Source #

Open a file for reading, using the standard System.IO.openFile. This opens the handle in text mode, using the initial system locale's text encoding.

readFileOrStdinPortably :: String -> IO Text Source #

Like readFilePortably, but read from standard input if the path is "-".

readFileOrStdinPortably' :: Maybe DynEncoding -> String -> IO Text Source #

Like readFileOrStdinPortably, but take an optional converter.

readFileStrictly :: FilePath -> IO Text Source #

Like readFilePortably, but read all of the file before proceeding.

readFilePortably :: FilePath -> IO Text Source #

Read text from a file, converting any rn line endings to n,, using the system locale's text encoding, ignoring any utf8 BOM prefix (as seen in paypal's 2018 CSV, eg) if that encoding is utf8.

hGetContentsPortably :: Maybe DynEncoding -> Handle -> IO Text Source #

Read text from a handle, perhaps using a specified encoding from the encoding package. Or if no encoding is specified, using the handle's current encoding, changing it to UTF-8BOM if it was UTF-8, to ignore any Byte Order Mark at the start. Also it converts Windows line endings to newlines. If decoding fails, this throws an IOException (or possibly a UnicodeException or something else from the encoding package).

textToHandle :: Text -> IO Handle Source #

Create a handle from which the given text can be read. Its encoding will be UTF-8.

# Command line parsing

progArgs :: [String] Source #

The program's command line arguments. Uses unsafePerformIO; tends to stick in GHCI until reloaded, and may or may not detect args provided by a hledger config file.

getFlag :: [String] -> IO Bool Source #

Given one or more long or short flag names, report whether this flag is present in the command line. Concatenated short flags (-a -b written as -ab) are not supported.

getOpt :: [String] -> IO (Maybe String) Source #

Given one or more long or short option names, read the rightmost value of this option from the command line arguments. If the value is missing raise an error. Concatenated short flags (-a -b written as -ab) are not supported.

parseYN :: String -> Either String Bool Source #

Parse yyesalways or nnonever to true or false, or return an error message.

parseYNA :: String -> Either String YNA Source #

Parse yyesalways or nnonever or a/auto to a YNA choice, or return an error message.

data YNA Source #

Constructors

Yes |
No |
Auto |

#### Instances

Instances details

Show YNA Source # |
Instance details Defined in Hledger.Utils.IO Methods showsPrec :: Int -> YNA -> ShowS Source # show :: YNA -> String Source # showList :: [YNA] -> ShowS Source #
Eq YNA Source # |
Instance details Defined in Hledger.Utils.IO Methods (==) :: YNA -> YNA -> Bool Source # (/=) :: YNA -> YNA -> Bool Source #

# Terminal size

getTerminalHeightWidth :: IO (Maybe (Int, Int)) Source #

An alternative to ansi-terminal's getTerminalSize, based on the more robust-looking terminal-size package.

Tries to get stdout's terminal's current height and width.

getTerminalHeight :: IO (Maybe Int) Source #

getTerminalWidth :: IO (Maybe Int) Source #

# Pager output

findPager :: IO (Maybe String) Source #

Try to find a pager executable robustly, safely handling various error conditions like an unset PATH var or the specified pager not being found as an executable. The pager can be specified by a path or program name in the PAGER environment variable. If that is unset or has a problem, "less" is tried, then "more". If successful, the pager's path or program name is returned.

runPager :: String -> IO () Source #

Display the given text on the terminal, trying to use a pager ($PAGER, less, or more) when appropriate (see maybePagerFor), otherwise printing to standard output. Also, if the pager is less, we modify the LESS environment variable (see lessVarValue) and check for problems which could cause confusing output (see lessIsWorking).

lessVarValue :: Maybe String -> Maybe String -> Bool -> String Source #

Compute the LESS environment variable value that hledger will use for the less pager. This used in runPager when invoking less, and also in the setup command for display. It takes the current HLEDGER_LESS and LESS env var values, and whether we are showing colour on stdout, and returns the adjusted LESS value that should be used. Specifically:

- If HLEDGER_LESS is defined, we use it in place of the LESS environment variable.
- Otherwise, if LESS is defined, append some preferred options (lessOptions and maybe lessColourOptions) to it.
- Otherwise, we set LESS to just use those preferred options.

lessIsWorking :: Maybe [(String, String)] -> IO Bool Source #

Test `less`, by running less --version and looking for a nonzero exit, timeout, or stderr output. Uses the provided environment, containing a LESS variable, if any. We do this because various LESS settings can cause some less versions to fail or cause confusing output without failing.

# ANSI colour/styles

## hledger-specific

colorOption :: IO YNA Source #

Get the value of the rightmost --color or --colour option from the program's command line arguments. Throws an error if the option's value could not be parsed.

useColorOnStdout :: IO Bool Source #

Should ANSI color and styles be used for standard output ? Considers useColorOnHandle stdout and hasOutputFile.

useColorOnStderr :: IO Bool Source #

Should ANSI color and styles be used for standard error output ? Considers useColorOnHandle stderr; is not affected by an --output-file option.

useColorOnStdoutUnsafe :: Bool Source #

Like useColorOnStdout, but using unsafePerformIO. Useful eg for low-level debug code. Sticky in GHCI until reloaded, may not always be affected by --color in a hledger config file, etc.

useColorOnStderrUnsafe :: Bool Source #

Like useColorOnStdoutUnsafe, but for stderr.

bold' :: String -> String Source #

Set various ANSI styles/colours in a string, only if useColorOnStdoutUnsafe says we should.

faint' :: String -> String Source #

black' :: String -> String Source #

red' :: String -> String Source #

green' :: String -> String Source #

yellow' :: String -> String Source #

blue' :: String -> String Source #

magenta' :: String -> String Source #

cyan' :: String -> String Source #

white' :: String -> String Source #

brightBlack' :: String -> String Source #

brightRed' :: String -> String Source #

brightGreen' :: String -> String Source #

brightYellow' :: String -> String Source #

brightBlue' :: String -> String Source #

brightMagenta' :: String -> String Source #

brightCyan' :: String -> String Source #

brightWhite' :: String -> String Source #

rgb' :: Float -> Float -> Float -> String -> String Source #

sgrresetall :: String Source #

## Generic

color :: ColorIntensity -> Color -> String -> String Source #

Wrap a string in ANSI codes to set and reset foreground colour. ColorIntensity is `Dull` or `Vivid` (ie normal and bold). Color is one of `Black`, `Red`, `Green`, `Yellow`, `Blue`, `Magenta`, `Cyan`, `White`. Eg: `color Dull Red "text"`.

bgColor :: ColorIntensity -> Color -> String -> String Source #

Wrap a string in ANSI codes to set and reset background colour.

colorB :: ColorIntensity -> Color -> WideBuilder -> WideBuilder Source #

Wrap a WideBuilder in ANSI codes to set and reset foreground colour.

bgColorB :: ColorIntensity -> Color -> WideBuilder -> WideBuilder Source #

Wrap a WideBuilder in ANSI codes to set and reset background colour.

terminalIsLight :: Maybe Bool Source #

Detect whether the terminal currently has a light background colour, if possible, using unsafePerformIO. If the terminal is transparent, its apparent light/darkness may be different.

terminalLightness :: Maybe Float Source #

Detect the terminal's current background lightness (0..1), if possible, using unsafePerformIO. If the terminal is transparent, its apparent lightness may be different.

terminalFgColor :: Maybe (RGB Float) Source #

Detect the terminal's current foreground colour, if possible, using unsafePerformIO.

terminalBgColor :: Maybe (RGB Float) Source #

Detect the terminal's current background colour, if possible, using unsafePerformIO.