-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from reflex-frp/aa-vty-widgets
Extract vty widgets into a library module
- Loading branch information
Showing
5 changed files
with
157 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
{-| | ||
- Module: Reflex.Vty.GHCi | ||
- Description: Vty widgets useful when building your own GHCi runner | ||
-} | ||
{-# LANGUAGE FlexibleContexts #-} | ||
{-# LANGUAGE MultiWayIf #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE RecursiveDo #-} | ||
module Reflex.Vty.GHCi where | ||
|
||
import Control.Monad ((<=<), void) | ||
import Control.Monad.Fix (MonadFix) | ||
import Data.ByteString (ByteString) | ||
import qualified Data.Text as T | ||
import qualified Data.Text.Encoding as T | ||
import Reflex.Network | ||
import Reflex.Process | ||
import Reflex.Process.GHCi | ||
import Reflex.Vty | ||
|
||
-- | Display the overall status of the GHCi session, including exit information in case GHCi has quit | ||
statusDisplay | ||
:: ( PostBuild t m | ||
, MonadHold t m | ||
) | ||
=> Ghci t | ||
-> VtyWidget t m () | ||
statusDisplay g = do | ||
pb <- getPostBuild | ||
text <=< hold "" $ leftmost | ||
[ statusMessage <$> updated (_ghci_status g) | ||
, statusMessage <$> tag (current $ _ghci_status g) pb | ||
, ("Command exited with " <>) . T.pack . show <$> _process_exit (_ghci_process g) | ||
] | ||
|
||
-- | A scrollable widget that displays a message at the bottom of the widget | ||
-- when there is additional content to view. | ||
scrollableOutput | ||
:: ( Reflex t | ||
, MonadNodeId m | ||
, MonadHold t m | ||
, MonadFix m | ||
, PostBuild t m | ||
) | ||
=> Behavior t ByteString | ||
-> VtyWidget t m () | ||
scrollableOutput out = col $ do | ||
dh <- displayHeight | ||
scroll <- stretch $ scrollableText never $ T.decodeUtf8 <$> out | ||
fixed 1 $ text $ | ||
let f h (ix, n) = if n - ix + 1 > h | ||
then "↓ More ↓" | ||
else "" | ||
in f <$> current dh <*> scroll | ||
|
||
-- | A scrollable widget that scrolls down as output goes past the end of the widget | ||
scrollingOutput | ||
:: ( Reflex t | ||
, Monad m | ||
, MonadHold t m | ||
, MonadFix m | ||
) | ||
=> Dynamic t ByteString | ||
-> VtyWidget t m () | ||
scrollingOutput out = do | ||
dh <- displayHeight | ||
let scrollBy h (ix, n) = | ||
if | ix == 0 && n <= h -> Nothing -- Scrolled to the top and we don't have to scroll down | ||
| n > h && n - ix - h == 0 -> Just 1 | ||
| otherwise -> Nothing | ||
rec scroll <- scrollableText (tagMaybe (scrollBy <$> current dh <*> scroll) $ updated out) $ | ||
T.decodeUtf8 <$> current out | ||
return () | ||
|
||
-- | Display the output GHCi produces when it's loading the requested modules (e.g., warnings) | ||
ghciModuleStatus | ||
:: ( MonadNodeId m | ||
, PostBuild t m | ||
, MonadHold t m | ||
, MonadFix m | ||
) | ||
=> Ghci t | ||
-> VtyWidget t m () | ||
ghciModuleStatus g = col $ do | ||
let ghciExit = _process_exit $ _ghci_process g | ||
ghciExited <- hold False $ True <$ ghciExit | ||
fixed 3 $ boxStatic def $ statusDisplay g | ||
out <- moduleOutput (not <$> ghciExited) g | ||
stretch $ scrollableOutput $ current out | ||
|
||
-- | Display the output of the expression GHCi is evaluating | ||
ghciExecOutput | ||
:: ( MonadHold t m | ||
, MonadFix m | ||
, Adjustable t m | ||
) | ||
=> Ghci t | ||
-> VtyWidget t m () | ||
ghciExecOutput g = do | ||
ghciExited <- hold False $ True <$ _process_exit (_ghci_process g) | ||
out <- execOutput (not <$> ghciExited) g | ||
-- Rebuild the entire output widget so that we don't have to worry about resetting scroll state | ||
_ <- networkHold (scrollingOutput out) $ ffor (_ghci_reload g) $ \_ -> scrollingOutput out | ||
return () | ||
|
||
-- | A widget that displays the module status and the execution status in two stacked, resizable panes | ||
ghciPanes | ||
:: ( Reflex t | ||
, MonadFix m | ||
, MonadHold t m | ||
, MonadNodeId m | ||
, PostBuild t m | ||
, Adjustable t m | ||
) | ||
=> Ghci t | ||
-> VtyWidget t m () | ||
ghciPanes g = void $ splitVDrag | ||
(hRule doubleBoxStyle) | ||
(ghciModuleStatus g) | ||
(ghciExecOutput g) |