-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Ungarble output from several threads -- -- Provides a simple interface for writing concurrent programs that need -- to output a lot of status messages to the console, or display multiple -- progress bars for different activities at the same time, or -- concurrently run external commands that output to the console. -- -- Built on top of that is a way of defining multiple output regions, -- which are automatically laid out on the screen and can be individually -- updated. Can be used for progress displays etc. -- @package concurrent-output @version 1.1.0 -- | Concurrent output handling. -- --
--   import Control.Concurrent.Async
--   import System.Console.Concurrent
--   
--   main = withConcurrentOutput $
--   	outputConcurrent "washed the car\n"
--   		`concurrently`
--   outputConcurrent "walked the dog\n"
--   	`concurrently`
--   	createProcessConcurrent (proc "ls" [])
--   
module System.Console.Concurrent -- | Use this around any actions that use outputConcurrent or -- createProcessConcurrent -- -- This is necessary to ensure that buffered concurrent output actually -- gets displayed before the program exits. withConcurrentOutput :: (MonadIO m, MonadMask m) => m a -> m a -- | Values that can be output. class Outputable v toOutput :: Outputable v => v -> ByteString -- | Displays a value to stdout. -- -- No newline is appended to the value, so if you want a newline, be sure -- to include it yourself. -- -- Uses locking to ensure that the whole output occurs atomically even -- when other threads are concurrently generating output. -- -- When something else is writing to the console at the same time, this -- does not block. It buffers the value, so it will be displayed once the -- other writer is done. outputConcurrent :: Outputable v => v -> IO () -- | Wrapper around createProcess that prevents multiple processes -- that are running concurrently from writing to stdout/stderr at the -- same time. -- -- If the process does not output to stdout or stderr, it's run by -- createProcess entirely as usual. Only processes that can generate -- output are handled specially: -- -- A process is allowed to write to stdout and stderr in the usual way, -- assuming it can successfully take the output lock. -- -- When the output lock is held (ie, by another concurrent process, or -- because outputConcurrent is being called at the same time), the -- process is instead run with its stdout and stderr redirected to a -- buffer. The buffered output will be displayed as soon as the output -- lock becomes free, or after the command has finished. createProcessConcurrent :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -- | This must be used to wait for processes started with -- createProcessConcurrent. -- -- This is necessary because waitForProcess has a race condition -- when two threads check the same process. If the race is triggered, one -- thread will successfully wait, but the other throws a DoesNotExist -- exception. waitForProcessConcurrent :: ProcessHandle -> IO ExitCode -- | Blocks until any processes started by createProcessConcurrent -- have finished, and any buffered output is displayed. -- -- withConcurrentOutput calls this at the end; you can call it -- anytime you want to flush output. flushConcurrentOutput :: IO () -- | Holds a lock while performing an action. This allows the action to -- perform its own output to the console, without using functions from -- this module. -- -- While this is running, other threads that try to lockOutput will -- block. Any calls to outputConcurrent and -- createProcessConcurrent will not block, but the output will be -- buffered and displayed only once the action is done. lockOutput :: (MonadIO m, MonadMask m) => m a -> m a -- | Buffered output. data OutputBuffer data StdHandle StdOut :: StdHandle StdErr :: StdHandle -- | Adds a value to the output buffer for later display. -- -- Note that buffering large quantities of data this way will keep it -- resident in memory until it can be displayed. While -- outputConcurrent uses temp files if the buffer gets too big, -- this STM function cannot do so. bufferOutputSTM :: Outputable v => StdHandle -> v -> STM () -- | A STM action that waits for some buffered output to become available, -- and returns it. -- -- The function can select a subset of output when only some is desired; -- the fst part is returned and the snd is left in the buffer. -- -- This will prevent it from being displayed in the usual way, so you'll -- need to use emitOutputBuffer to display it yourself. outputBufferWaiterSTM :: (OutputBuffer -> (OutputBuffer, OutputBuffer)) -> STM [(StdHandle, OutputBuffer)] waitAnyBuffer :: OutputBuffer -> (OutputBuffer, OutputBuffer) -- | Use with outputBufferWaiterSTM to make it only return buffered -- output that ends with a newline. Anything buffered without a newline -- is left in the buffer. waitCompleteLines :: OutputBuffer -> (OutputBuffer, OutputBuffer) -- | Emits the content of the OutputBuffer to the Handle -- -- If you use this, you should use lockOutput to ensure you're the -- only thread writing to the console. emitOutputBuffer :: StdHandle -> OutputBuffer -> IO () instance GHC.Classes.Eq System.Console.Concurrent.AtEnd instance GHC.Classes.Eq System.Console.Concurrent.OutputBuffer instance GHC.Classes.Eq System.Console.Concurrent.OutputBufferedActivity instance System.Console.Concurrent.Outputable Data.ByteString.Internal.ByteString instance System.Console.Concurrent.Outputable Data.Text.Internal.Text instance System.Console.Concurrent.Outputable GHC.Base.String -- | Console regions are displayed near the bottom of the console, and can -- be updated concurrently by threads. Any other output displayed using -- outputConcurrent and createProcessConcurrent will scroll -- up above the open console regions. -- -- For example, this program: -- --
--   import Control.Concurrent.Async
--   import Control.Concurrent
--   import System.Console.Concurrent
--   import System.Console.Regions
--   
--   main = displayConsoleRegions $ do
--   	mapConcurrently download [1..5] `concurrently` mapM_ message [1..10]
--   
--   message :: Int -> IO ()
--   message n = do
--   	threadDelay 500000
--   	outputConcurrent ("Message " ++ show n ++ "\n")
--   
--   download :: Int -> IO ()
--   download n = withConsoleRegion Linear $ \r -> do
--   	setConsoleRegion r basemsg
--   	go n r
--     where
--   	basemsg = "Download " ++ show n
--   go c r
--   	| c < 1 = finishConsoleRegion r (basemsg ++ " done!")
--   		| otherwise = do
--   			threadDelay 1000000
--   			appendConsoleRegion r " ... "
--   			go (c-1) r
--   
-- -- Will display like this: -- --
--   Message 1
--   Message 2
--   Download 1 ...
--   Download 2 ...
--   Download 3 ...
--   
-- -- Once the 1st download has finished, and another message has displayed, -- the console will update like this: -- --
--   Message 1
--   Message 2
--   Download 1 done!
--   Message 3
--   Download 2 ... ...
--   Download 3 ... ...
--   
module System.Console.Regions -- | Handles all display for the other functions in this module. -- -- Note that this uses lockOutput, so it takes over all output to -- the console while the passed IO action is running. As well as -- displaying the console regions, this handles display of anything -- buffered by outputConcurrent and -- createProcessConcurrent. -- -- When standard output is not an ANSI capable terminal, console regions -- are not displayed. displayConsoleRegions :: (MonadIO m, MonadMask m) => m a -> m a data ConsoleRegionHandle -- | Controls how a region is laid out in the console. -- -- Here's an annotated example of how the console layout works. -- --
--   scrolling......
--   scrolling......
--   scrolling......
--   aaaaaa......... -- Linear
--   bbbbbbbbbbbbbbb -- Linear
--   bbb............       (expanded to multiple lines)
--   ccccccccc...... -- Linear
--   ddd eee fffffff -- [InLine]
--   ffff ggggg.....       (expanded to multiple lines)
--   
data RegionLayout Linear :: RegionLayout InLine :: ConsoleRegionHandle -> RegionLayout -- | Runs the action with a new console region, closing the region when the -- action finishes or on exception. withConsoleRegion :: (MonadIO m, MonadMask m) => RegionLayout -> (ConsoleRegionHandle -> m a) -> m a -- | Opens a new console region for output. openConsoleRegion :: RegionLayout -> IO ConsoleRegionHandle -- | Closes a console region. Once closed, the region is removed from the -- display. closeConsoleRegion :: ConsoleRegionHandle -> IO () -- | Sets the value to display within a console region. setConsoleRegion :: Outputable v => ConsoleRegionHandle -> v -> IO () -- | Appends the value to whatever was already on display within a console -- region. appendConsoleRegion :: Outputable v => ConsoleRegionHandle -> v -> IO () -- | Closes the console region and displays the passed value in the -- scrolling area above the active console regions. finishConsoleRegion :: Outputable v => ConsoleRegionHandle -> v -> IO () -- | STM version of openConsoleRegion. Allows atomically opening -- multiple regions at the same time, which guarantees they are on -- adjacent lines. -- --
--   [r1, r2, r3] <- atomically $
--   replicateM 3 (openConsoleRegionSTM Linear)
--   
openConsoleRegionSTM :: RegionLayout -> STM ConsoleRegionHandle closeConsoleRegionSTM :: ConsoleRegionHandle -> STM () setConsoleRegionSTM :: Outputable v => ConsoleRegionHandle -> v -> STM () appendConsoleRegionSTM :: Outputable v => ConsoleRegionHandle -> v -> STM () -- | Updates the list of regions. The list is ordered from the bottom of -- the screen up. Reordering it will change the order in which regions -- are displayed. It's also fine to remove, duplicate, or add new regions -- to the list. updateRegionListSTM :: ([ConsoleRegionHandle] -> [ConsoleRegionHandle]) -> STM () instance GHC.Classes.Eq System.Console.Regions.RegionLayout instance GHC.Classes.Eq System.Console.Regions.ConsoleRegionHandle instance GHC.Classes.Eq System.Console.Regions.Region