ansi-terminal 0.10 → 0.10.1
raw patch · 8 files changed
+105/−30 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ System.Console.ANSI: hGetCursorPosition :: Handle -> IO (Maybe (Int, Int))
+ System.Console.ANSI: hGetTerminalSize :: Handle -> IO (Maybe (Int, Int))
Files
- CHANGELOG.md +9/−0
- ansi-terminal.cabal +1/−1
- src/System/Console/ANSI.hs +23/−0
- src/System/Console/ANSI/Unix.hs +11/−6
- src/System/Console/ANSI/Windows.hs +2/−2
- src/System/Console/ANSI/Windows/Emulator.hs +5/−5
- src/includes/Common-Include.hs +52/−16
- src/includes/Exports-Include.hs +2/−0
CHANGELOG.md view
@@ -1,6 +1,15 @@ Changes ======= +Version 0.10.1 +-------------- + +* Add `hGetCursorPosition` and `hGetTerminalSize`. +* On Unix-like operating systems, fix a bug where `getReportedCursorPosition` + could block indefinitely if no information was forthcoming on the console + input stream. +* Improvements to Haddock documentation. + Version 0.10 ------------
ansi-terminal.cabal view
@@ -1,5 +1,5 @@ Name: ansi-terminal -Version: 0.10 +Version: 0.10.1 Cabal-Version: >= 1.8 Category: User Interfaces Synopsis: Simple ANSI terminal support, with Windows compatibility
src/System/Console/ANSI.hs view
@@ -23,6 +23,10 @@ * Changing the title of the terminal +A terminal that supports control character sequences acts on them when they +are flushed from the output buffer (with a newline character @\"\\n\"@ or, for +the standard output channel, @hFlush stdout@). + The functions moving the cursor to an absolute position are 0-based (the top-left corner is considered to be at row 0 column 0) (see 'setCursorPosition') and so is 'getCursorPosition0'. The \'ANSI\' standards themselves are 1-based @@ -88,12 +92,31 @@ > import System.Console.ANSI > > -- Set colors and write some text in those colors. +> main :: IO () > main = do > setSGR [SetColor Foreground Vivid Red] > setSGR [SetColor Background Vivid Blue] > putStrLn "Red-On-Blue" > setSGR [Reset] -- Reset to default colour scheme > putStrLn "Default colors." + +Another example: + +> module Main where +> +> import System.IO (hFlush, stdout) +> import System.Console.ANSI +> +> main :: IO () +> main = do +> setSGR [SetColor Foreground Dull Blue] +> putStr "Enter your name: " +> setSGR [SetColor Foreground Dull Yellow] +> hFlush stdout -- flush the output buffer before getLine +> name <- getLine +> setSGR [SetColor Foreground Dull Blue] +> putStrLn $ "Hello, " ++ name ++ "!" +> setSGR [Reset] -- reset to default colour scheme For many more examples, see the project's extensive <https://github.com/feuerbach/ansi-terminal/blob/master/app/Example.hs Example.hs> file.
src/System/Console/ANSI/Unix.hs view
@@ -9,9 +9,11 @@ #include "Exports-Include.hs" ) where +import Data.Maybe (fromMaybe) import Control.Exception.Base (bracket) import System.IO (BufferMode (..), Handle, hGetBuffering, hGetEcho, hIsTerminalDevice, hIsWritable, hPutStr, hSetBuffering, hSetEcho, stdin) +import System.Timeout (timeout) import Text.ParserCombinators.ReadP (readP_to_S) import System.Console.ANSI.Codes @@ -81,7 +83,10 @@ -- (See Common-Include.hs for Haddock documentation) getReportedCursorPosition = bracket (hGetEcho stdin) (hSetEcho stdin) $ \_ -> do hSetEcho stdin False -- Turn echo off - get + -- If, unexpectedly, no data is available on the console input stream then + -- the timeout will prevent the getChar blocking. For consistency with the + -- Windows equivalent, returns "" if the expected information is unavailable. + fromMaybe "" <$> timeout 500000 get -- 500 milliseconds where get = do c <- getChar @@ -98,9 +103,9 @@ -- in order to avoid O(n^2) complexity. else return $ reverse (c:s) -- Reverse the order of the built list. --- getCursorPosition0 :: IO (Maybe (Int, Int)) +-- hGetCursorPosition :: Handle -> IO (Maybe (Int, Int)) -- (See Common-Include.hs for Haddock documentation) -getCursorPosition0 = fmap to0base <$> getCursorPosition +hGetCursorPosition h = fmap to0base <$> getCursorPosition where to0base (row, col) = (row - 1, col - 1) getCursorPosition = do @@ -109,9 +114,9 @@ -- buffer will be discarded, so this needs -- to be done before the cursor positon is -- emitted) - reportCursorPosition - hFlush stdout -- ensure the report cursor position code is sent to the - -- operating system + hReportCursorPosition h + hFlush h -- ensure the report cursor position code is sent to the + -- operating system getReportedCursorPosition case readP_to_S cursorPosition input of [] -> return Nothing
src/System/Console/ANSI/Windows.hs view
@@ -191,6 +191,6 @@ -- (See Common-Include.hs for Haddock documentation) getReportedCursorPosition = E.getReportedCursorPosition --- getCursorPosition0 :: IO (Maybe (Int, Int)) +-- hGetCursorPosition :: Handle -> IO (Maybe (Int, Int)) -- (See Common-Include.hs for Haddock documentation) -getCursorPosition0 = E.getCursorPosition0 +hGetCursorPosition = E.hGetCursorPosition
src/System/Console/ANSI/Windows/Emulator.hs view
@@ -477,18 +477,18 @@ isKeyDown = keyEventKeyDown keyEventRecord isKeyDownEvent = eventType == 1 && isKeyDown --- getCursorPosition0 :: IO (Maybe (Int, Int)) +-- hGetCursorPosition :: Handle -> IO (Maybe (Int, Int)) -- (See Common-Include.hs for Haddock documentation) -getCursorPosition0 = fmap to0base <$> getCursorPosition +hGetCursorPosition h = fmap to0base <$> getCursorPosition where to0base (row, col) = (row - 1, col - 1) getCursorPosition = CE.catch getCursorPosition' getCPExceptionHandler where getCursorPosition' = do withHandleToHANDLE stdin flush -- Flush the console input buffer - reportCursorPosition - hFlush stdout -- ensure the report cursor position code is sent to the - -- operating system + hReportCursorPosition h + hFlush h -- ensure the report cursor position code is sent to the + -- operating system input <- getReportedCursorPosition case readP_to_S cursorPosition input of [] -> return Nothing
src/includes/Common-Include.hs view
@@ -5,12 +5,12 @@ -- documentation. #if !MIN_VERSION_base(4,8,0) -import Control.Applicative +import Control.Applicative ((<*>)) +import Data.Functor ((<$>)) #endif import Control.Monad (void) import Data.Char (isDigit) -import Data.Functor ((<$>)) import System.Environment (getEnvironment) import System.IO (hFlush, stdout) import Text.ParserCombinators.ReadP (char, many1, ReadP, satisfy) @@ -227,10 +227,12 @@ -- 'reportCursorPosition', 'getReportedCursorPosition' and 'cursorPosition'. Any -- position @(row, column)@ is translated to be 0-based (that is, the top-left -- corner is at @(0, 0)@), consistent with `setCursorColumn` and --- `setCursorPosition`. (Note that the information emitted by --- 'reportCursorPosition' is 1-based.) Returns 'Nothing' if any data emitted by --- 'reportCursorPosition', obtained by 'getReportedCursorPosition', cannot be --- parsed by 'cursorPosition'. +-- `setCursorPosition`. (Note that the information emitted into the console +-- input stream by 'reportCursorPosition' is 1-based.) Returns 'Nothing' if any +-- data emitted by 'reportCursorPosition', obtained by +-- 'getReportedCursorPosition', cannot be parsed by 'cursorPosition'. Uses +-- 'stdout'. If 'stdout' will be redirected, see 'hGetCursorPosition' for a more +-- general function. -- -- On Windows operating systems, the function is not supported on consoles, such -- as mintty, that are not based on the Win32 console of the Windows API. @@ -238,10 +240,30 @@ -- -- @since 0.8.2 getCursorPosition0 :: IO (Maybe (Int, Int)) +getCursorPosition0 = hGetCursorPosition stdout +-- | Attempts to get the reported cursor position, combining the functions +-- 'hReportCursorPosition' (with the specified handle), +-- 'getReportedCursorPosition' and 'cursorPosition'. Any position +-- @(row, column)@ is translated to be 0-based (that is, the top-left corner is +-- at @(0, 0)@), consistent with 'hSetCursorColumn' and 'hSetCursorPosition'. +-- (Note that the information emitted into the console input stream by +-- 'hReportCursorPosition' is 1-based.) Returns 'Nothing' if any data emitted by +-- 'hReportCursorPosition', obtained by 'getReportedCursorPosition', cannot be +-- parsed by 'cursorPosition'. +-- +-- On Windows operating systems, the function is not supported on consoles, such +-- as mintty, that are not based on the Win32 console of the Windows API. +-- (Command Prompt and PowerShell are based on the Win32 console.) +-- +-- @since 0.10.1 +hGetCursorPosition :: Handle -> IO (Maybe (Int, Int)) + -- | Attempts to get the current terminal size (height in rows, width in --- columns), by using `getCursorPosition0` after attempting to set the cursor --- position beyond the bottom right corner of the terminal. +-- columns), by using 'getCursorPosition0' to query the console input stream +-- after attempting to set the cursor position beyond the bottom right corner of +-- the terminal. Uses 'stdout'. If 'stdout' will be redirected, see +-- 'hGetTerminalSize' for a more general function. -- -- On Windows operating systems, the function is not supported on consoles, such -- as mintty, that are not based on the Win32 console of the Windows API. @@ -249,12 +271,26 @@ -- -- @since 0.9 getTerminalSize :: IO (Maybe (Int, Int)) -getTerminalSize = do - saveCursor - setCursorPosition 999 999 -- Attempt to set the cursor position beyond the - -- bottom right corner of the terminal. - mPos <- getCursorPosition0 - restoreCursor - hFlush stdout -- ensure the restore cursor position code is sent to the - -- operating system +getTerminalSize = hGetTerminalSize stdout + +-- | Attempts to get the current terminal size (height in rows, width in +-- columns), by writing control character sequences to the specified handle +-- (which will typically be 'stdout' or 'stderr') and using 'hGetCursorPosition' +-- to query the console input stream after attempting to set the cursor position +-- beyond the bottom right corner of the terminal. +-- +-- On Windows operating systems, the function is not supported on consoles, such +-- as mintty, that are not based on the Win32 console of the Windows API. +-- (Command Prompt and PowerShell are based on the Win32 console.) +-- +-- @since 0.10.1 +hGetTerminalSize :: Handle -> IO (Maybe (Int, Int)) +hGetTerminalSize h = do + hSaveCursor h + hSetCursorPosition h 999 999 -- Attempt to set the cursor position beyond the + -- bottom right corner of the terminal. + mPos <- hGetCursorPosition h + hRestoreCursor h + hFlush h -- ensure the restore cursor position code is sent to the + -- operating system return $ fmap (\(r, c) -> (r + 1, c + 1)) mPos
src/includes/Exports-Include.hs view
@@ -112,8 +112,10 @@ -- * Getting the cursor position , getCursorPosition0 + , hGetCursorPosition , getReportedCursorPosition , cursorPosition -- * Getting the terminal size , getTerminalSize + , hGetTerminalSize