### Haskeline User Preferences Example Source: https://github.com/haskell/haskeline/wiki/UserPreferences Example configuration for the ~/.haskeline file, demonstrating various preference settings. ```Haskeline editMode: Vi completionType: MenuCompletion maxhistorysize: Just 40 ``` -------------------------------- ### Run a REPL with custom settings Source: https://context7.com/haskell/haskeline/llms.txt This example shows how to run a REPL with custom `Settings`, including a history file, enabling `autoAddHistory`, and disabling completion. ```haskell import System.Console.Haskeline -- With custom settings: history file and no auto-completion main2 :: IO () main2 = runInputT settings loop where settings = defaultSettings { historyFile = Just "/tmp/myapp_history" , autoAddHistory = True , complete = noCompletion } loop :: InputT IO () loop = do minput <- getInputLine "> " case minput of Nothing -> outputStrLn "Goodbye!" Just s -> outputStrLn ("Echo: " ++ s) >> loop ``` -------------------------------- ### Run a basic REPL with default settings Source: https://context7.com/haskell/haskeline/llms.txt This example demonstrates a basic REPL using `runInputT` with `defaultSettings`. It reads lines, echoes them back, and quits on 'quit' or Ctrl-D. ```haskell import System.Console.Haskeline -- Basic REPL using runInputT main :: IO () main = runInputT defaultSettings loop where loop :: InputT IO () loop = do minput <- getInputLine "% " case minput of Nothing -> return () -- Ctrl-D / EOF Just "quit" -> return () Just input -> do outputStrLn $ "You said: " ++ input loop ``` -------------------------------- ### Read input with pre-filled text Source: https://context7.com/haskell/haskeline/llms.txt This example uses `getInputLineWithInitial` to pre-populate the input buffer. It shows how to split the initial text around the cursor position. ```haskell import System.Console.Haskeline editLoop :: InputT IO () editLoop = do -- Cursor starts at end of "Hello, " minput <- getInputLineWithInitial "Edit> " ("Hello, ", "") case minput of Nothing -> return () Just s -> outputStrLn ("Result: " ++ s) -- Cursor starts between "foo " and "baz" minput2 <- getInputLineWithInitial "Edit> " ("foo ", "baz") case minput2 of Nothing -> return () Just s -> outputStrLn ("Result: " ++ s) ``` -------------------------------- ### Sequence Macros for Auto-Closing Brackets Source: https://github.com/haskell/haskeline/wiki/CustomKeyBindings Defines sequence macros to automatically insert closing brackets and position the cursor. For example, pressing '(' inserts '()' and moves the cursor left. ```haskeline bind: { { } left bind: ( ( ) left bind: [ [ ] left bind: } right bind: ] right bind: ) right ``` -------------------------------- ### ANSI color sequences in prompts Source: https://context7.com/haskell/haskeline/llms.txt Demonstrates how to use ANSI escape sequences in prompts, ensuring accurate line-wrapping by terminating sequences with `\STX`. ```APIDOC ## ANSI color sequences in prompts Haskeline correctly accounts for the width of ANSI escape sequences in prompts so that line-wrapping is accurate. Each escape sequence must be terminated with the `\STX` (ASCII 0x02) character to mark it as zero-width. On Windows, such sequences are ignored. ### `colorRepl` Example of a colored prompt using ANSI escape codes. ```haskell import System.Console.Haskeline -- Green prompt using ANSI escape codes -- \ESC[1;32m = bold green, \STX marks end of zero-width span -- \ESC[0m = reset color colorRepl :: InputT IO () colorRepl = do minput <- getInputLine "\ESC[1;32m\STXhaskell>\ESC[0m\STX " case minput of Nothing -> return () Just s -> outputStrLn ("Got: " ++ s) >> colorRepl main :: IO () main = runInputT defaultSettings colorRepl ``` ``` -------------------------------- ### Configure Input Session Settings Source: https://context7.com/haskell/haskeline/llms.txt Customize the input session using `Settings`, controlling features like tab completion, history files, and automatic history insertion. `setComplete` is useful for type inference when defining custom completion functions. ```haskell import System.Console.Haskeline import System.Console.Haskeline.Completion (completeWord, simpleCompletion) -- Custom completion for a small set of keywords keywordCompletion :: Monad m => CompletionFunc m keywordCompletion = completeWord Nothing " \t" $ \w -> return [ simpleCompletion kw | kw <- ["help", "quit", "load", "save", "run"] , w `isPrefixOf` kw ] where isPrefixOf p s = take (length p) s == p mySettings :: Settings IO mySettings = defaultSettings { complete = keywordCompletion , historyFile = Just "~/.myapp_history" , autoAddHistory = True } main :: IO () main = runInputT mySettings $ do minput <- getInputLine "cmd> " case minput of Nothing -> return () Just s -> outputStrLn $ "Command: " ++ s ``` -------------------------------- ### Hybrid Filename and Keyword Tab Completion in Haskell Source: https://context7.com/haskell/haskeline/llms.txt Combines keyword completion with filename completion. `fallbackCompletion` tries the first completion function and falls back to the second if no matches are found. Requires `System.Console.Haskeline` and `System.Console.Haskeline.Completion`. ```haskell import System.Console.Haskeline import System.Console.Haskeline.Completion -- fallbackCompletion: try keyword completion first, fall back to filenames hybridCompletion :: MonadIO m => CompletionFunc m hybridCompletion = fallbackCompletion keywordComp completeFilename where keywordComp = completeWord Nothing " " $ \w -> return [simpleCompletion k | k <- ["help","quit"], w `isPrefixOf` k] isPrefixOf p s = take (length p) s == p main :: IO () main = runInputT (setComplete hybridCompletion defaultSettings) $ do mf <- getInputLine "file> " case mf of Nothing -> return () Just f -> outputStrLn $ "Selected: " ++ f ``` -------------------------------- ### `Settings` Source: https://context7.com/haskell/haskeline/llms.txt Configuration object for the input session, controlling features like tab completion, history file location, and automatic history insertion. The `setComplete` function can be used to avoid type-inference issues when setting the `complete` field. ```APIDOC ## `Settings` — Configuring the input session `Settings` controls tab completion, history file location, and automatic history insertion. Use `setComplete` to avoid type-inference issues when setting `complete`. ### Type ```haskell data Settings m = Settings { complete :: CompletionFunc m, historyFile :: Maybe FilePath, autoAddHistory :: Bool -- ... other settings } defaultSettings :: Monad m => Settings m ``` ### Example ```haskell import System.Console.Haskeline import System.Console.Haskeline.Completion (completeWord, simpleCompletion) -- Custom completion for a small set of keywords keywordCompletion :: Monad m => CompletionFunc m keywordCompletion = completeWord Nothing " \t" $ \w -> return [ simpleCompletion kw | kw <- ["help", "quit", "load", "save", "run"] , w `isPrefixOf` kw ] where isPrefixOf p s = take (length p) s == p mySettings :: Settings IO mySettings = defaultSettings { complete = keywordCompletion , historyFile = Just "~/.myapp_history" , autoAddHistory = True } main :: IO () main = runInputT mySettings $ do minput <- getInputLine "cmd> " case minput of Nothing -> return () Just s -> outputStrLn $ "Command: " ++ s ``` ``` -------------------------------- ### Context-Sensitive Word Completion in Haskell Source: https://context7.com/haskell/haskeline/llms.txt Implement context-aware tab completion for words. `completeWordWithPrev` allows completion logic to consider text before the current word. Requires `System.Console.Haskeline` and `System.Console.Haskeline.Completion`. ```haskell import System.Console.Haskeline import System.Console.Haskeline.Completion -- Context-sensitive: complete different words based on the command contextCompletion :: Monad m => CompletionFunc m contextCompletion = completeWordWithPrev Nothing " " complete' where complete' prev word | "load " `isSuffixOf` prev = -- after "load", complete file-like names return [ simpleCompletion f | f <- ["config.json", "data.csv", "schema.sql"] , word `isPrefixOf` f ] | otherwise = return [ simpleCompletion c | c <- ["load", "save", "quit", "help"] , word `isPrefixOf` c ] isPrefixOf p s = take (length p) s == p isSuffix suf s = drop (length s - length suf) s == suf main :: IO () main = runInputT (setComplete contextCompletion defaultSettings) loop where loop = getInputLine "> " >>= maybe (return ()) (\_ -> loop) ``` -------------------------------- ### Force file-style input with Haskeline Source: https://context7.com/haskell/haskeline/llms.txt Use `useFile` to force Haskeline to read commands from a specified file, simulating script-style input. This is useful for testing or running predefined command sequences. ```haskell import System.Console.Haskeline import System.IO (openFile, hClose, IOMode(..)) -- Force file-style interaction from a script file scriptMode :: IO () scriptMode = runInputTBehavior (useFile "commands.txt") defaultSettings loop where loop = getInputLine "" >>= maybe (return ()) (\s -> outputStrLn s >> loop) ``` -------------------------------- ### Read one line of input with prompt Source: https://context7.com/haskell/haskeline/llms.txt This snippet demonstrates reading a single line of input using `getInputLine`. It handles exiting on Ctrl-D, repeating the prompt for blank lines, and processing other input. ```haskell import System.Console.Haskeline repl :: InputT IO () repl = do minput <- getInputLine "haskell> " case minput of Nothing -> outputStrLn "Exiting." Just "" -> repl -- blank line: repeat prompt Just "quit" -> outputStrLn "Bye!" Just line -> do outputStrLn $ "Evaluating: " ++ line repl ``` -------------------------------- ### Stateful IO API Source: https://context7.com/haskell/haskeline/llms.txt Provides an imperative, MVar-based interface for programs that cannot use `InputT` as a monad transformer, using `queryInput` to dispatch actions. ```APIDOC ## Stateful IO API (`System.Console.Haskeline.IO`) `System.Console.Haskeline.IO` provides an imperative, MVar-based interface for programs that cannot use `InputT` as a monad transformer. A background thread runs the Haskeline session; actions are dispatched to it via `queryInput`. ### `main` Example usage of the stateful IO API with `initializeInput`, `queryInput`, and `cancelInput`. ```haskell import System.Console.Haskeline import System.Console.Haskeline.IO import Control.Exception (bracketOnError) main :: IO () main = bracketOnError (initializeInput defaultSettings) cancelInput -- called only on exception (e.g., SigINT) (\hd -> loop hd >> closeInput hd) where loop :: InputState -> IO () loop hd = do minput <- queryInput hd (getInputLine "io> ") case minput of Nothing -> return () Just "quit" -> return () Just input -> do queryInput hd $ outputStrLn $ "Echo: " ++ input loop hd ``` ``` -------------------------------- ### Behavior Control Source: https://context7.com/haskell/haskeline/llms.txt Demonstrates how to control Haskeline's terminal interaction behavior using different `Behavior` settings like `useFile`, `preferTerm`, and `useTermHandles`. ```APIDOC ## `Behavior` — Controlling terminal interaction mode `Behavior` selects how Haskeline interacts with the terminal. Beyond `defaultBehavior`, you can force file-style input, force terminal-style input, or drive Haskeline against custom handles (e.g., a PTY or serial port). POSIX-only behaviors are not available on Windows. ### `scriptMode` Force file-style interaction from a script file. ```haskell import System.Console.Haskeline import System.IO (openFile, hClose, IOMode(..)) scriptMode :: IO () scriptMode = runInputTBehavior (useFile "commands.txt") defaultSettings loop where loop = getInputLine "" >>= maybe (return ()) (\s -> outputStrLn s >> loop) ``` ### `forceTerminal` Always use terminal, even if stdin is a pipe. ```haskell import System.Console.Haskeline forceTerminal :: IO () forceTerminal = runInputTBehavior preferTerm defaultSettings $ do minput <- getInputLine "force-term> " case minput of Nothing -> return () Just s -> outputStrLn $ "Got: " ++ s ``` ### `devTtyMode` (POSIX-only) POSIX: drive Haskeline against /dev/tty explicitly. ```haskell import System.Console.Haskeline import System.IO (openFile, hClose, IOMode(..)) devTtyMode :: IO () devTtyMode = do inp <- openFile "/dev/tty" ReadMode out <- openFile "/dev/tty" WriteMode runInputTBehavior (useTermHandles inp out) defaultSettings $ do minput <- getInputLine "tty> " case minput of Nothing -> return () Just s -> outputStrLn $ "Got: " ++ s hClose inp hClose out ``` ``` -------------------------------- ### `waitForAnyKey` Source: https://context7.com/haskell/haskeline/llms.txt Blocks execution until any key is pressed by the user. Returns `True` if a key was received, and `False` if EOF (Ctrl-D) is encountered. Useful for prompts like 'Press any key to continue...'. ```APIDOC ## `waitForAnyKey` — Wait for a keypress Blocks until any key is pressed. Returns `True` if a key was received, `False` on EOF / Ctrl-D. Useful for "press any key to continue" prompts. ### Usage ```haskell waitForAnyKey :: MonadIO m => String -> InputT m Bool ``` ### Example ```haskell import System.Console.Haskeline pausePrompt :: InputT IO () pausePrompt = do outputStrLn "Processing done." ok <- waitForAnyKey "Press any key to continue..." if ok then outputStrLn "Continuing." else outputStrLn "EOF received, exiting." ``` ``` -------------------------------- ### Wait for Keypress Source: https://context7.com/haskell/haskeline/llms.txt Use `waitForAnyKey` to pause execution until the user presses any key. It returns `True` if a key is received and `False` if EOF is encountered, useful for 'press any key to continue' prompts. ```haskell import System.Console.Haskeline pausePrompt :: InputT IO () pausePrompt = do outputStrLn "Processing done." ok <- waitForAnyKey "Press any key to continue..." if ok then outputStrLn "Continuing." else outputStrLn "EOF received, exiting." ``` -------------------------------- ### runInputT Source: https://context7.com/haskell/haskeline/llms.txt Runs an InputT action using default behavior, providing terminal-style interaction when stdin is a terminal or file-style interaction otherwise. User preferences are read automatically from ~/.haskeline in terminal mode. ```APIDOC ## runInputT — Run a line-reading application Runs an `InputT` action using `defaultBehavior`: terminal-style interaction when stdin is a terminal with echoing enabled, file-style interaction otherwise. User preferences are read automatically from `~/.haskeline` in terminal mode. ### Usage ```haskell runInputT :: MonadIO m => Settings (InputT m) -> InputT m a -> m a ``` ### Example ```haskell import System.Console.Haskeline -- Basic REPL using runInputT main :: IO () main = runInputT defaultSettings loop where loop :: InputT IO () loop = do minput <- getInputLine "% " case minput of Nothing -> return () -- Ctrl-D / EOF Just "quit" -> return () Just input -> do outputStrLn $ "You said: " ++ input loop -- With custom settings: history file and no auto-completion main2 :: IO () main2 = runInputT settings loop where settings = defaultSettings { historyFile = Just "/tmp/myapp_history" , autoAddHistory = True , complete = noCompletion } loop :: InputT IO () loop = do minput <- getInputLine "> " case minput of Nothing -> outputStrLn "Goodbye!" Just s -> outputStrLn ("Echo: " ++ s) >> loop ``` ``` -------------------------------- ### getInputLineWithInitial Source: https://context7.com/haskell/haskeline/llms.txt Like getInputLine, but pre-populates the editing area. The tuple argument splits the initial text: the first element appears to the left of the cursor, the second to the right. ```APIDOC ## getInputLineWithInitial — Read input with pre-filled text Like `getInputLine`, but pre-populates the editing area. The tuple argument splits the initial text: the first element appears to the left of the cursor, the second to the right. ### Usage ```haskell getInputLineWithInitial :: MonadIO m => String -> (String, String) -> InputT m (Maybe String) ``` ### Example ```haskell import System.Console.Haskeline editLoop :: InputT IO () editLoop = do -- Cursor starts at end of "Hello, " minput <- getInputLineWithInitial "Edit> " ("Hello, ", "") case minput of Nothing -> return () Just s -> outputStrLn ("Result: " ++ s) -- Cursor starts between "foo " and "baz" minput2 <- getInputLineWithInitial "Edit> " ("foo ", "baz") case minput2 of Nothing -> return () Just s -> outputStrLn ("Result: " ++ s) ``` ``` -------------------------------- ### Customizing User Preferences in Haskell Console Applications Source: https://context7.com/haskell/haskeline/llms.txt Allows overriding default user preferences like edit mode, completion style, and history settings. Use `readPrefs` to load from a file and `runInputTWithPrefs` to apply them. Requires `System.Console.Haskeline` and `System.Console.Haskeline.Prefs`. ```haskell import System.Console.Haskeline import System.Console.Haskeline.Prefs -- ~/.haskeline file contents: -- editMode: Vi -- completionType: MenuCompletion -- maxHistorySize: Just 200 -- historyDuplicates: IgnoreConsecutive -- bellStyle: NoBell -- Override prefs programmatically main :: IO () main = do prefs <- readPrefs "/etc/myapp/haskeline" runInputTWithPrefs prefs defaultSettings $ do minput <- getInputLine "vi-mode> " case minput of Nothing -> return () Just s -> outputStrLn $ "Input: " ++ s ``` -------------------------------- ### Configure Vi Mode and Key Bindings in Haskeline Source: https://github.com/haskell/haskeline/wiki/ViModeCompatibility Set Haskeline to Vi edit mode and bind keys for history navigation. Note that 'k' is translated to 'up' in both command and insert modes, which might affect intended behavior. ```haskeline editMode: Vi bind: k up bind: j down ``` -------------------------------- ### Drive Haskeline against /dev/tty on POSIX Source: https://context7.com/haskell/haskeline/llms.txt On POSIX systems, `useTermHandles` allows explicitly driving Haskeline against specific input and output handles, such as `/dev/tty`. This provides fine-grained control over terminal interaction. ```haskell -- POSIX: drive Haskeline against /dev/tty explicitly -- (useTermHandles and useTermHandlesWith, not available on Windows) devTtyMode :: IO () devTtyMode = do inp <- openFile "/dev/tty" ReadMode out <- openFile "/dev/tty" WriteMode runInputTBehavior (useTermHandles inp out) defaultSettings $ do minput <- getInputLine "tty> " case minput of Nothing -> return () Just s -> outputStrLn $ "Got: " ++ s hClose inp hClose out ``` -------------------------------- ### Haskell History API for Console Input Source: https://context7.com/haskell/haskeline/llms.txt Provides programmatic control over command history. Use `getHistory`, `modifyHistory`, `putHistory`, `readHistory`, and `writeHistory` for advanced history management. Requires `System.Console.Haskeline` and `System.Console.Haskeline.History`. ```haskell import System.Console.Haskeline import System.Console.Haskeline.History historyDemo :: InputT IO () historyDemo = do -- Inspect current history hist <- getHistory let ls = historyLines hist outputStrLn $ "History has " ++ show (length ls) ++ " entries." -- Manually add an entry modifyHistory (addHistory "synthetic entry") -- Limit history to 50 lines modifyHistory (stifleHistory (Just 50)) -- Replace history entirely putHistory emptyHistory outputStrLn "History cleared." -- Read history from a file saved <- liftIO $ readHistory "/tmp/saved_history" putHistory saved -- Write current history to a file final <- getHistory liftIO $ writeHistory "/tmp/saved_history" final ``` -------------------------------- ### Bind Ctrl-Left/Right to Skip Words Source: https://github.com/haskell/haskeline/wiki/CustomKeyBindings Configures Ctrl-Left and Ctrl-Right to skip words, leveraging default meta-b and meta-f bindings. This requires additional 'keyseq' definitions on POSIX systems to map the control sequences. ```haskeline bind: ctrl-left meta-b bind: ctrl-right meta-f ``` ```haskeline keyseq: "\ESC[5D" ctrl-left keyseq: "\ESC[5C" ctrl-right ``` ```haskeline keyseq: xterm-color "\ESC[5D" ctrl-left keyseq: xterm-color "\ESC[5C" ctrl-right keyseq: xterm "\ESC[1;5D" ctrl-left keyseq: xterm "\ESC[1;5C" ctrl-right ``` -------------------------------- ### Stateful IO API for Haskeline Source: https://context7.com/haskell/haskeline/llms.txt The `System.Console.Haskeline.IO` module provides an imperative, MVar-based interface for programs that cannot use `InputT`. Actions are dispatched to a background thread via `queryInput`. ```haskell import System.Console.Haskeline import System.Console.Haskeline.IO import Control.Exception (bracketOnError) main :: IO () main = bracketOnError (initializeInput defaultSettings) cancelInput -- called only on exception (e.g., SigINT) (\hd -> loop hd >> closeInput hd) where loop :: InputState -> IO () loop hd = do minput <- queryInput hd (getInputLine "io> ") case minput of Nothing -> return () Just "quit" -> return () Just input -> do queryInput hd $ outputStrLn $ "Echo: " ++ input loop hd ``` -------------------------------- ### `outputStr` / `outputStrLn` Source: https://context7.com/haskell/haskeline/llms.txt Outputs Unicode text to the user's standard output in a manner that is safe for cross-platform use. `outputStrLn` automatically appends a newline character after the text. ```APIDOC ## `outputStr` / `outputStrLn` — Output Unicode text Write text to the user's standard output in a Unicode-safe, cross-platform manner. `outputStrLn` appends a newline. ### Usage ```haskell outputStr :: MonadIO m => String -> InputT m () outputStrLn :: MonadIO m => String -> InputT m () ``` ### Example ```haskell import System.Console.Haskeline printResults :: [String] -> InputT IO () printResults results = do outputStrLn "Results:" mapM_ (\r -> outputStr " • " >> outputStrLn r) results outputStr "(end)" -- no trailing newline ``` ``` -------------------------------- ### GHCi: Configure Green Prompt with Haskeline Source: https://github.com/haskell/haskeline/wiki/ControlSequencesInPrompt Adds a green prompt to GHCi by setting the 'prompt' option in '~/.ghci'. This configuration uses escape sequences to set the text color to green and then reset it. Ensure GHCi is compiled with haskeline-0.6.3 or newer. ```GHCi :set prompt "\ESC[1;32m\STX%s>\ESC[0m\STX" ``` -------------------------------- ### Run InputT actions in the base monad with withRunInBase Source: https://context7.com/haskell/haskeline/llms.txt Use `withRunInBase` to obtain a runner function that executes `InputT` actions within the base monad. This is particularly useful when passing `InputT` actions to functions that require a base-monad callback, such as `forkIO`. ```haskell import System.Console.Haskeline import Control.Concurrent (forkIO) concurrentRepl :: InputT IO () concurrentRepl = withRunInBase $ \runInIO -> do _tid <- forkIO $ runInIO $ do outputStrLn "Background: starting..." result <- runInIO $ getInputLine "main> " case result of Nothing -> return () Just s -> runInIO $ outputStrLn ("Main got: " ++ s) ``` -------------------------------- ### Configure Tmux Escape Time Source: https://github.com/haskell/haskeline/wiki/UsingTmux Add this line to your `~/.tmux.conf` to prevent tmux from adding an extra delay after the escape key is pressed, which is beneficial when using vi-style bindings. ```tmux set -s escape-time 0 ``` -------------------------------- ### Haskeline: Prompt with Color Escape Sequences Source: https://github.com/haskell/haskeline/wiki/ControlSequencesInPrompt Demonstrates how to use escape sequences for colored prompts in Haskeline. The '\STX' character denotes the end of an escape sequence, allowing Haskeline to calculate prompt width correctly. The trailing '\STX' is not printed. ```Haskell getInputLine "\ESC[1;32m\STXPrompt:\ESC[0m\STX" ``` -------------------------------- ### Force terminal input with Haskeline Source: https://context7.com/haskell/haskeline/llms.txt Use `preferTerm` to ensure Haskeline always uses terminal-style input, even if standard input is redirected (e.g., from a pipe). This guarantees interactive behavior. ```haskell -- Always use terminal, even if stdin is a pipe forceTerminal :: IO () forceTerminal = runInputTBehavior preferTerm defaultSettings $ do minput <- getInputLine "force-term> " case minput of Nothing -> return () Just s -> outputStrLn $ "Got: " ++ s ``` -------------------------------- ### `getExternalPrint` Source: https://context7.com/haskell/haskeline/llms.txt Returns an `IO` action that can be used to print strings to the console without interfering with the current input prompt. This function is safe to call from other threads concurrently with user input. ```APIDOC ## `getExternalPrint` — Thread-safe printing function Returns an `IO` action that prints a string without interfering with the current input prompt. Safe to call from other threads concurrently with user input. ### Usage ```haskell getExternalPrint :: MonadIO m => m (String -> IO ()) ``` ### Example ```haskell import System.Console.Haskeline import Control.Concurrent (forkIO, threadDelay) concurrentExample :: InputT IO () concurrentExample = do printer <- getExternalPrint _ <- liftIO $ forkIO $ do threadDelay 2000000 printer "Background task finished!\n" minput <- getInputLine "Working... > " case minput of Nothing -> return () Just s -> liftIO $ printer ("You typed: " ++ s ++ "\n") ``` ``` -------------------------------- ### ReaderT API Source: https://context7.com/haskell/haskeline/llms.txt Exposes `InputT` as an ordinary `ReaderT` via `toReaderT` / `fromReaderT` for MTL-style or effect-system integration. ```APIDOC ## `ReaderT` API (`System.Console.Haskeline.ReaderT`) Since version 0.8.4.0, Haskeline exposes `InputT` as an ordinary `ReaderT` via `toReaderT` / `fromReaderT`. This allows MTL-style or effect-system integration without committing to `InputT` in the monad stack. ### `MonadHaskeline` typeclass MTL-style typeclass for Haskeline operations. ```haskell import System.Console.Haskeline qualified as H import System.Console.Haskeline.ReaderT import Control.Monad.Trans.Reader (ReaderT, runReaderT) -- MTL-style typeclass class Monad m => MonadHaskeline m where getLine' :: String -> m (Maybe String) ``` ### `App` monad and `runApp` Example of an `App` monad built on `ReaderT` and how to run it. ```haskell -- App monad built on ReaderT InputTEnv type App = ReaderT (InputTEnv IO) IO instance MonadHaskeline App where getLine' prompt = toReaderT (H.getInputLine prompt) runApp :: App () runApp = do minput <- getLine' "app> " case minput of Nothing -> return () Just s -> toReaderT $ H.outputStrLn ("Got: " ++ s) main :: IO () main = H.runInputT H.defaultSettings $ fromReaderT runApp ``` ``` -------------------------------- ### ReaderT API for Haskeline integration Source: https://context7.com/haskell/haskeline/llms.txt Exposes `InputT` as `ReaderT` for MTL-style or effect-system integration. This allows using Haskeline features without committing `InputT` to the monad stack. ```haskell import System.Console.Haskeline qualified as H import System.Console.Haskeline.ReaderT import Control.Monad.Trans.Reader (ReaderT, runReaderT) -- MTL-style typeclass class Monad m => MonadHaskeline m where getLine' :: String -> m (Maybe String) -- App monad built on ReaderT InputTEnv type App = ReaderT (InputTEnv IO) IO instance MonadHaskeline App where getLine' prompt = toReaderT (H.getInputLine prompt) runApp :: App () runApp = do minput <- getLine' "app> " case minput of Nothing -> return () Just s -> toReaderT $ H.outputStrLn ("Got: " ++ s) main :: IO () main = H.runInputT H.defaultSettings $ fromReaderT runApp ``` -------------------------------- ### `withInterrupt` / `handleInterrupt` Source: https://context7.com/haskell/haskeline/llms.txt Provides mechanisms for handling Ctrl-C signals. `withInterrupt` enables catching Ctrl-C as an `Interrupt` exception within a specified action, while `handleInterrupt` allows defining a specific handler for this exception. ```APIDOC ## `withInterrupt` / `handleInterrupt` — Ctrl-C handling `withInterrupt` enables catching Ctrl-C as an `Interrupt` exception within the given action. `handleInterrupt` provides a handler for that exception. Without these, pressing Ctrl-C may terminate the entire program. ### Usage ```haskell withInterrupt :: MonadIO m => InputT m a -> InputT m a handleInterrupt :: MonadIO m => InputT m () -> InputT m a -> InputT m a ``` ### Example ```haskell import System.Console.Haskeline safeLoop :: InputT IO () safeLoop = withInterrupt loop where loop = handleInterrupt onCancel $ do minput <- getInputLine "safe> " case minput of Nothing -> return () Just s -> outputStrLn ("Got: " ++ s) >> loop onCancel = do outputStrLn "^C caught — type 'quit' to exit." loop ``` ``` -------------------------------- ### ANSI color sequences in Haskeline prompts Source: https://context7.com/haskell/haskeline/llms.txt Haskeline correctly accounts for the width of ANSI escape sequences in prompts, ensuring accurate line wrapping. Terminate sequences with `\STX` (ASCII 0x02) to mark them as zero-width. ```haskell import System.Console.Haskeline -- Green prompt using ANSI escape codes -- \ESC[1;32m = bold green, \STX marks end of zero-width span -- \ESC[0m = reset color colorRepl :: InputT IO () colorRepl = do minput <- getInputLine "\ESC[1;32m\STXhaskell>\ESC[0m\STX " case minput of Nothing -> return () Just s -> outputStrLn ("Got: " ++ s) >> colorRepl main :: IO () main = runInputT defaultSettings colorRepl ``` -------------------------------- ### Bind Backspace Key Source: https://github.com/haskell/haskeline/wiki/CustomKeyBindings Remaps the backspace key to move left non-destructively and meta-backspace to delete the character to the left. ```haskeline bind: backspace left bind: meta-backspace backspace ``` -------------------------------- ### Read Password Without Echo Source: https://context7.com/haskell/haskeline/llms.txt Use `getPassword` to read sensitive input like passwords. Provide `Nothing` for no masking or `Just '*'` to display asterisks for each character typed. Returns `Nothing` on EOF. ```haskell import System.Console.Haskeline passwordExample :: InputT IO () passwordExample = do -- No mask: nothing displayed while typing mpass <- getPassword Nothing "Password: " case mpass of Nothing -> outputStrLn "Cancelled." Just p -> outputStrLn $ "Got password of length: " ++ show (length p) -- With '*' mask character mpass2 <- getPassword (Just '*') "Confirm: " case mpass2 of Nothing -> return () Just p -> outputStrLn $ "Confirmed: " ++ replicate (length p) '*' ``` -------------------------------- ### Output Unicode Text Source: https://context7.com/haskell/haskeline/llms.txt Employ `outputStr` and `outputStrLn` for cross-platform, Unicode-safe text output. `outputStrLn` automatically appends a newline character. ```haskell import System.Console.Haskeline printResults :: [String] -> InputT IO () printResults results = do outputStrLn "Results:" mapM_ (\r -> outputStr " • " >> outputStrLn r) results outputStr "(end)" -- no trailing newline ``` -------------------------------- ### Read a single character Source: https://context7.com/haskell/haskeline/llms.txt This snippet demonstrates reading a single printable character using `getInputChar`. It ignores non-printable characters and handles EOF. ```haskell import System.Console.Haskeline charLoop :: InputT IO () charLoop = do mc <- getInputChar "Press a key: " case mc of Nothing -> outputStrLn "EOF reached." Just 'q' -> outputStrLn "Quitting." Just c -> do outputStrLn $ "Got: " ++ [c] charLoop ``` -------------------------------- ### Thread-Safe Printing Source: https://context7.com/haskell/haskeline/llms.txt Obtain a thread-safe `IO` action using `getExternalPrint` to print messages without disrupting the current input prompt. This is safe for concurrent use from other threads. ```haskell import System.Console.Haskeline import Control.Concurrent (forkIO, threadDelay) concurrentExample :: InputT IO () concurrentExample = do printer <- getExternalPrint _ <- liftIO $ forkIO $ do threadDelay 2000000 printer "Background task finished!\n" minput <- getInputLine "Working... > " case minput of Nothing -> return () Just s -> liftIO $ printer ("You typed: " ++ s ++ "\n") ``` -------------------------------- ### Handle Ctrl-C Interruptions Source: https://context7.com/haskell/haskeline/llms.txt Use `withInterrupt` to enable catching Ctrl-C as an `Interrupt` exception and `handleInterrupt` to define a specific handler for it. This prevents Ctrl-C from terminating the entire program. ```haskell import System.Console.Haskeline safeLoop :: InputT IO () safeLoop = withInterrupt loop where loop = handleInterrupt onCancel $ do minput <- getInputLine "safe> " case minput of Nothing -> return () Just s -> outputStrLn ("Got: " ++ s) >> loop onCancel = do outputStrLn "^C caught — type 'quit' to exit." loop ``` -------------------------------- ### `getPassword` Source: https://context7.com/haskell/haskeline/llms.txt Reads a line of text from the console with echo suppressed. An optional masking character can be used to display characters on screen. Returns `Nothing` on EOF. ```APIDOC ## `getPassword` — Read a password without echo Reads a line of text with echo suppressed. An optional masking character replaces each typed character on screen. Returns `Nothing` on Ctrl-D / EOF. ### Usage ```haskell getPassword :: MonadIO m => Maybe Char -> String -> InputT m (Maybe String) ``` ### Example ```haskell import System.Console.Haskeline passwordExample :: InputT IO () passwordExample = do -- No mask: nothing displayed while typing mpass <- getPassword Nothing "Password: " case mpass of Nothing -> outputStrLn "Cancelled." Just p -> outputStrLn $ "Got password of length: " ++ show (length p) -- With '*' mask character mpass2 <- getPassword (Just '*') "Confirm: " case mpass2 of Nothing -> return () Just p -> outputStrLn $ "Confirmed: " ++ replicate (length p) '*' ``` ``` -------------------------------- ### getInputLine Source: https://context7.com/haskell/haskeline/llms.txt Reads a single line from the user, providing a rich editing interface in terminal mode. Returns Nothing on Ctrl-D (empty line) or EOF. Automatically adds non-blank lines to history when autoAddHistory is True. ```APIDOC ## getInputLine — Read one line of input Reads a single line from the user, providing a rich editing interface in terminal mode. Returns `Nothing` on Ctrl-D (empty line) or EOF. Automatically adds non-blank lines to history when `autoAddHistory` is `True`. ### Usage ```haskell getInputLine :: MonadIO m => String -> InputT m (Maybe String) ``` ### Example ```haskell import System.Console.Haskeline repl :: InputT IO () repl = do minput <- getInputLine "haskell> " case minput of Nothing -> outputStrLn "Exiting." Just "" -> repl -- blank line: repeat prompt Just "quit" -> outputStrLn "Bye!" Just line -> do outputStrLn $ "Evaluating: " ++ line repl ``` ``` -------------------------------- ### getInputChar Source: https://context7.com/haskell/haskeline/llms.txt Reads one printable character without waiting for a newline (in terminal mode). Non-printable characters are ignored. Returns Nothing on Ctrl-D / EOF. ```APIDOC ## getInputChar — Read a single character Reads one printable character without waiting for a newline (in terminal mode). Non-printable characters are ignored. Returns `Nothing` on Ctrl-D / EOF. ### Usage ```haskell getInputChar :: MonadIO m => String -> InputT m (Maybe Char) ``` ### Example ```haskell import System.Console.Haskeline charLoop :: InputT IO () charLoop = do mc <- getInputChar "Press a key: " case mc of Nothing -> outputStrLn "EOF reached." Just 'q' -> outputStrLn "Quitting." Just c -> do outputStrLn $ "Got: " ++ [c] charLoop ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.