Blame includes/Common-Include.hs

Packit fc89b4
-- This file contains code that is common to modules System.Console.ANSI.Unix,
Packit fc89b4
-- System.Console.ANSI.Windows and System.Console.ANSI.Windows.Emulator, such as
Packit fc89b4
-- type signatures and the definition of functions specific to stdout in terms
Packit fc89b4
-- of the corresponding more general functions, inclduding the related Haddock
Packit fc89b4
-- documentation.
Packit fc89b4
Packit fc89b4
import System.Environment
Packit fc89b4
#if !MIN_VERSION_base(4,8,0)
Packit fc89b4
import Control.Applicative
Packit fc89b4
#endif
Packit fc89b4
Packit fc89b4
import Control.Monad (void)
Packit fc89b4
import Data.Char (isDigit)
Packit fc89b4
import Text.ParserCombinators.ReadP (char, many1, ReadP, satisfy)
Packit fc89b4
Packit fc89b4
hCursorUp, hCursorDown, hCursorForward, hCursorBackward
Packit fc89b4
    :: Handle
Packit fc89b4
    -> Int -- ^ Number of lines or characters to move
Packit fc89b4
    -> IO ()
Packit fc89b4
cursorUp, cursorDown, cursorForward, cursorBackward
Packit fc89b4
    :: Int -- ^ Number of lines or characters to move
Packit fc89b4
    -> IO ()
Packit fc89b4
cursorUp = hCursorUp stdout
Packit fc89b4
cursorDown = hCursorDown stdout
Packit fc89b4
cursorForward = hCursorForward stdout
Packit fc89b4
cursorBackward = hCursorBackward stdout
Packit fc89b4
Packit fc89b4
hCursorDownLine, hCursorUpLine :: Handle
Packit fc89b4
                               -> Int -- ^ Number of lines to move
Packit fc89b4
                               -> IO ()
Packit fc89b4
cursorDownLine, cursorUpLine :: Int -- ^ Number of lines to move
Packit fc89b4
                             -> IO ()
Packit fc89b4
cursorDownLine = hCursorDownLine stdout
Packit fc89b4
cursorUpLine = hCursorUpLine stdout
Packit fc89b4
Packit fc89b4
hSetCursorColumn :: Handle
Packit fc89b4
                 -> Int -- ^ 0-based column to move to
Packit fc89b4
                 -> IO ()
Packit fc89b4
setCursorColumn :: Int -- ^ 0-based column to move to
Packit fc89b4
                -> IO ()
Packit fc89b4
setCursorColumn = hSetCursorColumn stdout
Packit fc89b4
Packit fc89b4
hSetCursorPosition :: Handle
Packit fc89b4
                   -> Int -- ^ 0-based row to move to
Packit fc89b4
                   -> Int -- ^ 0-based column to move to
Packit fc89b4
                   -> IO ()
Packit fc89b4
setCursorPosition :: Int -- ^ 0-based row to move to
Packit fc89b4
                  -> Int -- ^ 0-based column to move to
Packit fc89b4
                  -> IO ()
Packit fc89b4
setCursorPosition = hSetCursorPosition stdout
Packit fc89b4
Packit fc89b4
hSaveCursor, hRestoreCursor, hReportCursorPosition :: Handle -> IO ()
Packit fc89b4
Packit fc89b4
-- | Save the cursor position in memory. The only way to access the saved value
Packit fc89b4
-- is with the 'restoreCursor' command.
Packit fc89b4
saveCursor :: IO ()
Packit fc89b4
-- | Restore the cursor position from memory. There will be no value saved in
Packit fc89b4
-- memory until the first use of the 'saveCursor' command.
Packit fc89b4
restoreCursor :: IO ()
Packit fc89b4
-- | Looking for a way to get the cursors position? See
Packit fc89b4
-- 'getCursorPosition'.
Packit fc89b4
--
Packit fc89b4
-- Emit the cursor position into the console input stream, immediately after
Packit fc89b4
-- being recognised on the output stream, as:
Packit fc89b4
-- @ESC [ \<cursor row> ; \<cursor column> R@
Packit fc89b4
--
Packit fc89b4
-- In isolation of 'getReportedCursorPosition' or 'getCursorPosition', this
Packit fc89b4
-- function may be of limited use on Windows operating systems because of
Packit fc89b4
-- difficulties in obtaining the data emitted into the console input stream.
Packit fc89b4
-- The function 'hGetBufNonBlocking' in module "System.IO" does not work on
Packit fc89b4
-- Windows. This has been attributed to the lack of non-blocking primatives in
Packit fc89b4
-- the operating system (see the GHC bug report #806 at
Packit fc89b4
-- <https://ghc.haskell.org/trac/ghc/ticket/806>).
Packit fc89b4
reportCursorPosition :: IO ()
Packit fc89b4
Packit fc89b4
saveCursor = hSaveCursor stdout
Packit fc89b4
restoreCursor = hRestoreCursor stdout
Packit fc89b4
reportCursorPosition = hReportCursorPosition stdout
Packit fc89b4
Packit fc89b4
hHideCursor, hShowCursor :: Handle
Packit fc89b4
                         -> IO ()
Packit fc89b4
hideCursor, showCursor :: IO ()
Packit fc89b4
hideCursor = hHideCursor stdout
Packit fc89b4
showCursor = hShowCursor stdout
Packit fc89b4
Packit fc89b4
-- | Set the terminal window title
Packit fc89b4
hSetTitle :: Handle
Packit fc89b4
          -> String -- ^ New title
Packit fc89b4
          -> IO ()
Packit fc89b4
-- | Set the terminal window title
Packit fc89b4
setTitle :: String -- ^ New title
Packit fc89b4
         -> IO ()
Packit fc89b4
setTitle = hSetTitle stdout
Packit fc89b4
Packit fc89b4
-- | Use heuristics to determine whether the functions defined in this
Packit fc89b4
-- package will work with a given handle.
Packit fc89b4
--
Packit fc89b4
-- The current implementation checks that the handle is a terminal, and
Packit fc89b4
-- that the @TERM@ environment variable doesn't say @dumb@ (which is what
Packit fc89b4
-- Emacs sets for its own terminal).
Packit fc89b4
hSupportsANSI :: Handle -> IO Bool
Packit fc89b4
-- Borrowed from an HSpec patch by Simon Hengel
Packit fc89b4
-- (https://github.com/hspec/hspec/commit/d932f03317e0e2bd08c85b23903fb8616ae642bd)
Packit fc89b4
hSupportsANSI h = (&&) <$> hIsTerminalDevice h <*> (not <$> isDumb)
Packit fc89b4
  where
Packit fc89b4
    -- cannot use lookupEnv since it only appeared in GHC 7.6
Packit fc89b4
    isDumb = maybe False (== "dumb") . lookup "TERM" <$> getEnvironment
Packit fc89b4
Packit fc89b4
-- | Parses the characters emitted by 'reportCursorPosition' into the console
Packit fc89b4
-- input stream. Returns the cursor row and column as a tuple.
Packit fc89b4
--
Packit fc89b4
-- For example, if the characters emitted by 'reportCursorPosition' are in
Packit fc89b4
-- 'String' @input@ then the parser could be applied like this:
Packit fc89b4
--
Packit fc89b4
-- > let result = readP_to_S cursorPosition input
Packit fc89b4
-- > case result of
Packit fc89b4
-- >     [] -> putStrLn $ "Error: could not parse " ++ show input
Packit fc89b4
-- >     [((row, column), _)] -> putStrLn $ "The cursor was at row " ++ show row
Packit fc89b4
-- >         ++ " and column" ++ show column ++ "."
Packit fc89b4
-- >     (_:_) -> putStrLn $ "Error: parse not unique"
Packit fc89b4
--
Packit fc89b4
cursorPosition :: ReadP (Int, Int)
Packit fc89b4
cursorPosition = do
Packit fc89b4
    void $ char '\ESC'
Packit fc89b4
    void $ char '['
Packit fc89b4
    row <- decimal -- A non-negative whole decimal number
Packit fc89b4
    void $ char ';'
Packit fc89b4
    col <- decimal -- A non-negative whole decimal number
Packit fc89b4
    void $ char 'R'
Packit fc89b4
    return (read row, read col)
Packit fc89b4
  where
Packit fc89b4
    digit = satisfy isDigit
Packit fc89b4
    decimal = many1 digit
Packit fc89b4
Packit fc89b4
-- | Attempts to get the reported cursor position data from the console input
Packit fc89b4
-- stream. The function is intended to be called immediately after
Packit fc89b4
-- 'reportCursorPosition' (or related functions) have caused characters to be
Packit fc89b4
-- emitted into the stream.
Packit fc89b4
--
Packit fc89b4
-- For example, on a Unix-like operating system:
Packit fc89b4
--
Packit fc89b4
-- > hSetBuffering stdin NoBuffering -- set no buffering (the contents of the
Packit fc89b4
-- >                                 -- buffer will be discarded, so this needs
Packit fc89b4
-- >                                 -- to be done before the cursor positon is
Packit fc89b4
-- >                                 -- emitted)
Packit fc89b4
-- > reportCursorPosition
Packit fc89b4
-- > hFlush stdout -- ensure the report cursor position code is sent to the
Packit fc89b4
-- >               -- operating system
Packit fc89b4
-- > input <- getReportedCursorPosition
Packit fc89b4
--
Packit fc89b4
-- On Windows operating systems, the function is not supported on consoles, such
Packit fc89b4
-- as mintty, that are not based on the Win32 console of the Windows API.
Packit fc89b4
-- (Command Prompt and PowerShell are based on the Win32 console.)
Packit fc89b4
getReportedCursorPosition :: IO String
Packit fc89b4
Packit fc89b4
-- | Attempts to get the reported cursor position, combining the functions
Packit fc89b4
-- 'reportCursorPosition', 'getReportedCursorPosition' and 'cursorPosition'.
Packit fc89b4
-- Returns 'Nothing' if any data emitted by 'reportCursorPosition', obtained by
Packit fc89b4
-- 'getReportedCursorPosition', cannot be parsed by 'cursorPosition'.
Packit fc89b4
--
Packit fc89b4
-- On Windows operating systems, the function is not supported on consoles, such
Packit fc89b4
-- as mintty, that are not based on the Win32 console of the Windows API.
Packit fc89b4
-- (Command Prompt and PowerShell are based on the Win32 console.)
Packit fc89b4
getCursorPosition :: IO (Maybe (Int, Int))