Copyright | 2015 Joey Hess <id@joeyh.name> |
---|---|
License | BSD-2-clause |
Safe Haskell | None |
Language | Haskell98 |
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 import System.Process main = displayConsoleRegions $ do mapConcurrently download [1..5] `concurrently` mapM_ message [1..10] `concurrently` createProcessConcurrent (proc "echo" ["hello world"]) 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 hello world 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 hello world Message 2 Download 1 done! Message 3 Download 2 ... ... Download 3 ... ...
- displayConsoleRegions :: (MonadIO m, MonadMask m) => m a -> m a
- data ConsoleRegionHandle
- data RegionLayout
- withConsoleRegion :: (MonadIO m, MonadMask m) => RegionLayout -> (ConsoleRegionHandle -> m a) -> m a
- openConsoleRegion :: RegionLayout -> IO ConsoleRegionHandle
- closeConsoleRegion :: ConsoleRegionHandle -> IO ()
- class Displayable v where
- toRegionContent :: v -> STM RegionContent
- setConsoleRegion :: Displayable v => ConsoleRegionHandle -> v -> IO ()
- appendConsoleRegion :: Outputable v => ConsoleRegionHandle -> v -> IO ()
- finishConsoleRegion :: Outputable v => ConsoleRegionHandle -> v -> IO ()
- openConsoleRegionSTM :: Displayable v => RegionLayout -> v -> STM ConsoleRegionHandle
- newConsoleRegionSTM :: Displayable v => RegionLayout -> v -> STM ConsoleRegionHandle
- closeConsoleRegionSTM :: ConsoleRegionHandle -> STM ()
- setConsoleRegionSTM :: Displayable v => ConsoleRegionHandle -> v -> STM ()
- appendConsoleRegionSTM :: Outputable v => ConsoleRegionHandle -> v -> STM ()
- data RegionContent
- = RegionContent (TVar Text)
- | RegionContentSTM (STM Text)
- readRegionContent :: ConsoleRegionHandle -> STM Text
- consoleSize :: TVar (Window Int)
- type Width = Int
- consoleWidth :: STM Width
- regionList :: TMVar [ConsoleRegionHandle]
Initialization
displayConsoleRegions :: (MonadIO m, MonadMask m) => m a -> m a Source
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.
data RegionLayout Source
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 ddddeeeefffffff -- [InLine] fffffggggg..... (expanded to multiple lines)
withConsoleRegion :: (MonadIO m, MonadMask m) => RegionLayout -> (ConsoleRegionHandle -> m a) -> m a Source
Runs the action with a new console region, closing the region when the action finishes or on exception.
openConsoleRegion :: RegionLayout -> IO ConsoleRegionHandle Source
Opens a new console region for output.
closeConsoleRegion :: ConsoleRegionHandle -> IO () Source
Closes a console region. Once closed, the region is removed from the display.
Region display
class Displayable v where Source
Values that can be displayed in a region.
toRegionContent :: v -> STM RegionContent Source
Displayable String Source | |
Displayable Text Source | |
Displayable (STM Text) Source | Makes a STM action be run to get the content of a region. Any change to the values that action reads will result in an immediate refresh of the display. |
setConsoleRegion :: Displayable v => ConsoleRegionHandle -> v -> IO () Source
Sets the value to display within a console region.
It's fine for the value to be longer than the terminal is wide, or to include newlines ('\n'). Regions expand to multiple lines as necessary.
The value can include ANSI SGR escape sequences for changing the colors etc of all or part of a region.
Other ANSI escape sequences, especially those doing cursor movement, will mess up the layouts of regions. Caveat emptor.
appendConsoleRegion :: Outputable v => ConsoleRegionHandle -> v -> IO () Source
Appends the value to whatever was already on display within a console region.
finishConsoleRegion :: Outputable v => ConsoleRegionHandle -> v -> IO () Source
Closes the console region and displays the passed value in the scrolling area above the active console regions.
STM interface
These actions can be composed into a STM transaction; once the transaction completes the console will be updated a single time to reflect all the changes made.
openConsoleRegionSTM :: Displayable v => RegionLayout -> v -> STM ConsoleRegionHandle Source
STM version of openConsoleRegion
. Allows atomically opening multiple
regions at the same time, which guarantees they are adjacent.
[r1, r2, r3] <- atomically $ replicateM 3 (openConsoleRegionSTM Linear T.empty)
newConsoleRegionSTM :: Displayable v => RegionLayout -> v -> STM ConsoleRegionHandle Source
Makes a new region, but does not add it to the display.
setConsoleRegionSTM :: Displayable v => ConsoleRegionHandle -> v -> STM () Source
STM version of setConsoleRegion
appendConsoleRegionSTM :: Outputable v => ConsoleRegionHandle -> v -> STM () Source
STM version of appendConsoleRegion
STM regions
The Displayable
instance for STM text can be used to
make regions that automatically update whenever there's
a change to any of the STM values that they use.
For example, a region that displays the screen size, and automatically refreshes it:
import System.Console.Terminal.Size import qualified Data.Text as T
r <- openConsoleRegion Linear s setConsoleRegion r $ do sz <- readTVar consoleSize return $ T.pack $ unwords [ "size:" , show (width sz) , "x" , show (height sz) ]
readRegionContent :: ConsoleRegionHandle -> STM Text Source
Reads the content of a region.
consoleSize :: TVar (Window Int) Source
On unix systems, this TVar is automatically updated when the terminal is resized.
regionList :: TMVar [ConsoleRegionHandle] Source
All the regions that are currently displayed on the screen.
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.