Code Monkey home page Code Monkey logo

brick's Introduction

brick is a Haskell terminal user interface (TUI) programming toolkit. To use it, you write a pure function that describes how your user interface should be drawn based on your current application state and you provide a state transformation function to handle events.

brick exposes a declarative API. Unlike most GUI toolkits which require you to write a long and tedious sequence of widget creations and layout setup, brick just requires you to describe your interface using a set of declarative layout combinators. Event-handling is done by pattern-matching on incoming events and updating your application state.

Under the hood, this library builds upon vty, so some knowledge of Vty will be necessary to use this library. Brick depends on vty-crossplatform, so Brick should work anywhere Vty works (Unix and Windows). Brick releases prior to 2.0 only support Unix-based systems.

Example

Here's an example interface (see programs/ReadmeDemo.hs):

joinBorders $
withBorderStyle unicode $
borderWithLabel (str "Hello!") $
(center (str "Left") <+> vBorder <+> center (str "Right"))

Result:

┌─────────Hello!─────────┐
│           │            │
│           │            │
│   Left    │   Right    │
│           │            │
│           │            │
└───────────┴────────────┘

Featured Projects

To get an idea of what some people have done with brick, check out these projects. If you have made something and would like me to include it, get in touch!

Project Description
2048Haskell An implementation of the 2048 game
babel-cards A TUI spaced-repetition memorization tool. Similar to Anki.
bhoogle A Hoogle client
brewsage A TUI for Homebrew
brick-trading-journal A TUI program that calculates basic statistics from trades
Brickudoku A hybrid of Tetris and Sudoku
cbookview A TUI for exploring polyglot chess opening book files
clifm A file manager
codenames-haskell An implementation of the Codenames game
fifteen An implementation of the 15 puzzle
ghcup A TUI for ghcup, the Haskell toolchain manager
git-brunch A git branch checkout utility
Giter A UI wrapper around Git CLI inspired by Magit.
gotta-go-fast A typing tutor
haradict A TUI Arabic dictionary powered by ElixirFM
hascard A program for reviewing "flash card" notes
haskell-player An afplay frontend
herms A command-line tool for managing kitchen recipes
hic-hac-hoe Play tic tac toe in terminal!
hledger-iadd An interactive terminal UI for adding hledger journal entries
hledger-ui A terminal UI for the hledger accounting system.
homodoro A terminal application to use the pomodoro technique and keep track of daily tasks
htyper A typing speed test program
hyahtzee2 Famous Yahtzee dice game
kpxhs An interactive Keepass database viewer
matterhorn A client for Mattermost
maze A Brick-based maze game
monalog Terminal logs observer
mushu An MPD client
mywork [Hackage] A tool to keep track of the projects you are working on
pboy A tiny PDF organizer
purebred A mail user agent
sandwich A test framework with a TUI interface
silly-joy An interpreter for Joy
solitaire The card game
sudoku-tui A Sudoku implementation
summoner-tui An interactive frontend to the Summoner tool
swarm A 2D programming and resource gathering game
tart A mouse-driven ASCII art drawing program
tetris An implementation of the Tetris game
thock A modern TUI typing game featuring online racing against friends
timeloop A time-travelling demonstrator
towerHanoi Animated solutions to The Tower of Hanoi
ttyme A TUI for Harvest
ullekha An interactive terminal notes/todo app with file/redis persistence
viewprof A GHC profile viewer
VOIDSPACE A space-themed typing-tutor game
wordle An implementation of the Wordle game
wrapping-editor An embeddable editor with support for Brick
youbrick A feed aggregator and launcher for Youtube channels

These third-party packages also extend brick:

Project Description
brick-filetree [Hackage] A widget for exploring a directory tree and selecting or flagging files and directories
brick-panes [Hackage] A Brick overlay library providing composition and isolation of screen areas for TUI apps.

Getting Started

Check out the many demo programs to get a feel for different aspects of the library:

$ cabal new-build -f demos
$ find dist-newstyle -type f -name \*-demo

To get started, see the user guide.

Documentation

Documentation for brick comes in a variety of forms:

Feature Overview

brick comes with a bunch of batteries included:

  • Vertical and horizontal box layout widgets
  • Basic single- and multi-line text editor widgets
  • List and table widgets
  • Progress bar widget
  • Simple dialog box widget
  • Border-drawing widgets (put borders around or in between things)
  • Generic scrollable viewports and viewport scroll bars
  • General-purpose layout control combinators
  • Extensible widget-building API
  • User-customizable attribute themes
  • Type-safe, validated input form API (see the Brick.Forms module)
  • A filesystem browser for file and directory selection
  • Borders can be configured to automatically connect!

Brick Discussion

There are two forums for discussing brick-related things:

  1. The Discussions page on the github repo, and
  2. The brick-users Google Group / e-mail list. You can subscribe here.

Status

There are some places were I have deliberately chosen to worry about performance later for the sake of spending more time on the design (and to wait on performance issues to arise first). brick is also something of an experimental project of mine and some aspects of the design involve trade-offs that might not be right for your application. Brick is not intended to be all things to all people; rather, I want it to provide a good foundation for building complex terminal interfaces in a declarative style to take away specific headaches of building, modifying, and working with such interfaces, all while seeing how far we can get with a pure function to specify the interface.

brick exports an extension API that makes it possible to make your own packages and widgets. If you use that, you'll also be helping to test whether the exported interface is usable and complete!

A note on Windows support

Brick supports Windows implicitly by way of Vty's Windows support. While I don't (and can't) personally test Brick on Windows hosts, it should be possible to use Brick on Windows. If you have any trouble, report any issues here. If needed, we'll migrate them to the vty-windows repository if they need to be fixed there.

Reporting bugs

Please file bug reports as GitHub issues. For best results:

  • Include the versions of relevant software packages: your terminal emulator, brick, ghc, vty, and Vty platform packages will be the most important ones.

  • Clearly describe the behavior you expected ...

  • ... and include a minimal demonstration program that exhibits the behavior you actually observed.

Contributing

If you decide to contribute, that's great! Here are some guidelines you should consider to make submitting patches easier for all concerned:

  • If you want to take on big things, talk to me first; let's have a design/vision discussion before you start coding. Create a GitHub issue and we can use that as the place to hash things out.
  • Please make changes consistent with the conventions I've used in the codebase.
  • Please adjust or provide Haddock and/or user guide documentation relevant to any changes you make.
  • Please ensure that commits are -Wall clean.
  • Please ensure that each commit makes a single, logical, isolated change as much as possible.
  • Please do not submit changes that your linter told you to make. I will probably decline them. Relatedly: please do not submit changes that change only style without changing functionality.
  • Please do NOT include package version changes in your patches. Package version changes are only done at release time when the full scope of a release's changes can be evaluated to determine the appropriate version change.

brick's People

Contributors

chhackett avatar dagit avatar diegospd avatar dmwit avatar eigengrau avatar franklinchen avatar frasertweedale avatar geekingfrog avatar hallettj avatar ibrahimsag avatar jchia avatar jhrcek avatar jtdaugherty avatar kintaro avatar kommusoft avatar kquick avatar ljwall avatar markus1189 avatar mlang avatar pkamenarsky avatar refaelsh avatar rhofour avatar romanofski avatar ryanglscott avatar sjakobi avatar smallhadroncollider avatar srhoulam avatar thomasjm avatar valyagolev avatar yvee1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

brick's Issues

Layers in Widget

Hi Jonathan,

thank you very much for the amazing "brick" library! It's great working with it. :)

I'm looking for a way to have layers within a "Widget", not just within an "App". I wondered if it would be possible to change the "image" in "Result" from "Image" to "[Image]", and then change "renderFinal" to flatten the "List" before passing it to "picForLayers"? Do you see any problems with that approach, and if not, would you be interested in integrating a patch if I would come up with the necessary changes?

Many thanks!

incorrect size for widget between horizontal borders

      l = list ...
      border = borderWithLabel label
      hborder w = hBorderWithLabel label
                  <=>
                  w
                  <=>
                  hBorder
      ui1 = border l
      ui2 = hborder l

ui1 is a list inside a border; it is sized correctly. ui2 is the same list without the side borders; it overflows the bottom of the screen by one or two rows, so you can't see the bottom border or the bottom-most list row.

Mouse support

Now that Vty has mouse support, there are some interesting possibilities for mouse support in Brick.

Dialog widget fixed width seems problematic

That the dialog widget is parametrised with a fixed width makes it very hard to use in a way, that would preclude crashes on terminal resize.

Most other widgets are resize-agnostic, yet the dialog isn't.

Linux only?

brick-0.5 depends on unix-2.7.1.0 which failed to install

Is windows support planned?

Making strict widgets greedy

I’d like to make a list, like so:

124   foo
4324  bar
1     test

Padding just adds space to the side on each line, so the result becomes something like

124   foo
4324   bar
1   test

The idea is to make the left part greedy and then restrict its size.
My naive approach ((hLimit 10 $ (txt "124") { hSize = Greedy }) <+> txt "foo" gives

124foo
…

It looks to me like it doesn’t make sense to reset hSize without re-rendering (what hLimit does).
How would I set a txt or str to greedy?
Does it even make sense to export the fields of Widgets?

Cannot build : DSO missing from command line

I've encountered a weird issue when compiling brick demos.
I'm following the instructions in the README, and run cabal install -j -f demos.

TL;DR :

undefined reference to symbol 'del_curterm'
/lib64/libtinfow.so.6: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

Unable to capture some modified key strokes.

I have a small demo using the following event loop

event :: State -> Event -> EventM (Next State)
event st e = do
    liftIO $ print e
    continue st

and the following draw function

draw :: State -> [Widget]
draw st = [str "Hello World!"]

There are several cases like Ctrl+,, Ctrl+., and Ctrl+/ that do not fire an event. Additionally there is at least one case of sending the wrong event. For example you would expect Ctrl+m to read...

EvKey (KChar 'm') [MCtrl]

however it actually reads...

EvKey KEnter []

Crashes when use hCenter, hLimit, and vBox together.

The following program crashes when the terminal width is less than max (min hlim a) (min hlim b), and this happens both when the initial terminal size is too small and when I manually resize terminal width after program start.

import Brick
import Brick.Widgets.Center

ui :: Widget
ui = hCenter . hLimit hlim $ vBox [s a 'A', s b 'B']
    where
    s x c = str . take x $ repeat c
    hlim = 100
    a = 60
    b = 40

main :: IO ()
main = simpleMain ui

The error I got is Main.hs: row 0 now exceeds region width.

Not sure if this is a duplicate of #47 .

Support optimized list rendering

Right now, the List rendering process utilizes the viewport feature to simplify scrolling state tracking. While that means the list supports variable-height list items, it means we pay a (possibly big) penalty since we render all list items regardless of visibility and then crop to show the ones in view. This works fine for small lists, but the delay in rendering becomes noticeable even for realistically sized lists (thousands of elements).

This clearly isn't great.

I initially thought supporting variable-height list items as well as uniform-height items would be a slam-dunk but I'm now thinking that an optimized list is really needed in the (common) case where you know that the heights of all of your list items will be the same number of rows. The only way we can know which subset of list elements to bother rendering is by knowing how high they will be in advance, a luxury we don't have if we assume the item heights can't be precomputed. But if we restrict ourselves to the assumption that the list items all have the same known height, we can use the scrolling state and viewport size to select only the items worth rendering.

I think this is feasible, but it might increase the burden on the user slightly and might have some trade-offs that need consideration. This ticket is a reminder for me to implement this and to jot down notes about what I have in mind.

(CC @simonmichael)

Editor bugs

Right now editors are showing a mysterious '...' character as well as failing to show more than the first line of text when being rendered. This might be related to recent string function changes.

Show instances for widgets would help debugging

I have been defining dummy Show instances for List, Editor etc. so that I can include them in my application types which need to be Showable for debugging, testing in GHCI etc.

instance Show (List a) where show _ = "<List>"
instance Show Editor   where show _ = "<Editor>"

How to always "scroll to bottom"/"crop from top where necessary"?

I would like behaviour where lines grow from bottom to top, for a greedy widget. lets say there is space for 10 lines. If there is one line of content, i want it to be at the bottom. if there are 20 lines of contents, i want 11-20 displayed.

I have played around with viewports/adding empty lines/translating; nothing gave this exact behaviour. closest was invoking visible on the bottom line; but then the viewport remains translated even if the available space increases (again). (Also, this solution feels kinda hacky.)

ansi escape codes don't work

import Brick
import System.Console.ANSI -- ansi-terminal

main = simpleMain (str (setSGRCode [SetColor Foreground Dull Red] ++ "hi"))

For some reason, this displays ... instead of a red hi

Dropdown menu

Is there a need for a dropdown menu? I came across a few instances where it might come in handy and would love to give a shot at it.

Can not readLine

brick causes some strage behaviour whith stdin
In this program (only little different from the hello world example) I read a String from stdin and display it.

module Main where
import Brick.Widgets.Core (str)
import Brick.Main (simpleMain)

main :: IO ()
main = do
  --text <- return "Hello world"
  text <- getLine
  simpleMain . str $ text

No big deal, right?
Wenn I do

ghc -threaded hello.hs
./hello
> hello you

everything works nicely ("hello you" is displayed).
But for

ghc -threaded hello.hs
echo "hello you" | ./hello

which should provide the same result, an error occurs (which wasn't noticed at compiletime, this never happend to me before):

hello: getTerminalAttributes: illegal operation (Inappropriate ioctl for device)

I don't get problems when replacing the simpleMain . str with putStrLn, so I guess this is a problem of brick. I am running ghc 7.10.2 on an Arch Linux and tried xterm, urxvt and termite (all with the same result.
Any idea what happens here?

Add brick to stackage

Please consider adding brick to stackage. The package already builds fine with GHC 8 and the stackage resolver:

$ cabal unpack brick
$ cd brick-0.8
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.0.1
$ stack init --resolver nightly --force --solver
...
$ stack build
...
Registering brick-0.8...

Expose `nextButtonBy` for `Dialog` widget

This is a feature request to expose another way than handleDialogEvent to change the state of a dialog widget. It would be nice to have support for arrows as well as tab/s-tab, and maybe something else.

So maybe directly expose (and document) nextButtonBy or expose simplified functions like nextChoice and prevChoice of type Dialog -> Dialog to handle that manually.
What do you think ?

re-initializing Editor widget with contents results in cursor being stuck at 1st line

Example (apply this diff to EditDemo.hs):

diff --git a/programs/EditDemo.hs b/programs/EditDemo.hs
index f300f88..05ad2f0 100644
--- a/programs/EditDemo.hs
+++ b/programs/EditDemo.hs
@@ -62,6 +62,7 @@ appEvent st ev =
         V.EvKey V.KEsc [] -> M.halt st
         V.EvKey (V.KChar '\t') [] -> M.continue $ switchEditors st
         V.EvKey V.KBackTab [] -> M.continue $ switchEditors st
+        V.EvKey (V.KChar ' ') [] -> M.continue st { _edit2 = (E.editor secondEditor (str . unlines) Nothing "hello\nworld")}
         _ -> M.continue =<< T.handleEventLensed st (currentEditorL st) ev

 initialState :: St

Then run it, press "TAB" (optional), then press SPACE to re-initialize/modify the 2nd editor widget to have the contents "hello\nworld". Although the words are rendered correctly (world being on the 2nd line), the cursor thinks that it's all on one line. It looks as if the cursor is hovering over extra blank space if you press Right arrow, but that appears to be the buffer where the word world is stored.

Tested on the latest 0.6.1 version by using cabal sandbox on GHC 7.10.3.

Get multiple, different colorized output for a list element

Not sure if this is a question or a feature request, but please bear with me.

From what I can tell, there is no way to assign multiple color attributes to text within a single List widget element.

What I have is basically a List of multiple strings, with each string being a particular "type", much like a spreadsheet. E.g.,

foo bar quux
foo bar quux
foo bar quux

and I want all the foo strings to be a certain color distinct from all the bar strings, and so on.

As I write this I realize that I could probably just have multiple List widgets, one for each "column" (one for foo, one for bar, etc.) and assign a different color attribute for each widget (and have them aligned horizontally, right?), but is there a way to just embed different colors into a single List widget item?
I feel that having multiple List widgets seems hacky and overly complicated.

Stack lts version is 0.4.1

This is not necessarily a bug, I just wanted to notify you, that the brick version on stackage lts is 0.4.1, for which most examples don't work. The nightly version is up to date, however, but you might want to include a note about this in the manual.

Thanks for this library!

inconsistent scroll position after listMoveTo

On a particular screen, the items are ordered by date, so on entering it I move the selection to the last (most recent) item:

initRegisterScreen d args st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScreen{}} =
  st{aScreen=s{rsState=is'}}
  where
    is' =
      listMoveTo (length items) $
      list (Name "register") (V.fromList items) 1
    items = ...

Sometimes the selected item appears at the bottom of the screen; sometimes it appears at the top (and I have to scroll up to see that there are older items). I'm not sure what controls this.

In this situation I think I'd like it to scroll down from the top just enough to reveal the selected item at the bottom of the screen.

Ideally I suppose there would be API to control List's scroll state (maybe it can expose a ViewportScroll ?)

Strange behavior when using hBox with unicode char

module Main where

import qualified Brick.Main as M
import qualified Brick.Widgets.Core as WC

ui = WC.vLimit h . WC.hLimit 5 $ WC.hBox
    [ WC.str text2 
    , WC.vLimit h $ WC.fill '$'
    ]
    where
    h = 3
    text1 = "    \n寬字\n    \n"
    text2 = "    \nabcd\n    \n"

main :: IO ()
main = M.simpleMain ui

The program displays

    $
abcd$
    $

But when I replace WC.str text2 by WC.str text1, it displays


寬字 

Both abcd and 寬字 occupy 4 display length in my terminal.
Maybe there is something wrong with wide character rendering?

Examples for more complex applications needed.

After reading the guide and looking at the example programs, I still have no idea how I am supposed to switch from one UI to another. For instance, I want to display a sublist after choosing a specific element of the main list and display a dialog after choosing a different element of the list. Is there any way to do that? I can do something similar by using multiple Apps like so

main = do
  a <- M.defaultMain listApp $ initialState ["subList1","subList2"]
  case (elem a) of
    Just (_,"subList1") -> M.defaultMain subList1App $ initialState [1..5]
    Just (_,"subList2") -> M.defaultMain subList2App $ initialState [5..10]

Now that works, but I don't think I'm supposed to use multiple Apps. Now I could just use the same App for everything, but then I can't use different header/footer for the different Lists without introducing a state datatype. Then there's also a problem when I want to go back from a sublist to the parent list. It would be nice if there was information on how to do these things.

lens usability improvements, examples ?

(micro)lens seems desirable for working with nested records in a brick app. I just started to exploring this, and am finding it harder than expected. Notes so far:

  • The first thing I want to use is (^.). Apparently this requires that the types it accesses are monoids. My records have brick Lists in them. You can't derive a Monoid instance for List because the constructors are hidden. I defined one manually for now:
instance Monoid (List a)
  where
    mempty      = list "" V.empty 1
    mappend a b = a & listElementsL .~ (a^.listElementsL <> b^.listElementsL)
  • I found myself wanting listSelectedElementL (and wrongly guessing listSelectedL was it).

Transparency for layers/pad functions

Hi,

first of all: I really like how this library feels, great job!

However, I have some problems laying out stuff for an ascii game. Consider two widgets I want to place in the top-right and bottom-left corner, respectively. I'd like that to work independent from the bounds of the containing widget. Is there a way without asking the container for its current size, e.g. reusing the pad* functions or something? It should also be composable, e.g. if I add other widgets to the container it should not influence the positioning of the already specified widgets.

What I had in mind was similar to having a separate layer for each widget and then just pad* Max, but unfortunately the padding characters aren't transparent.

What it boils down to, I guess, is: Is there a notion of transparency?

Paste support in the Editor

The Editor widget can now be modified to support bracketed pastes from Vty more efficiently than processing input events individually.

Brick visibility demo - ctrl-arrow up/down

The top-left and top-right viewports work as advertised. The bottom one does as expected for left-right movements, but ctrl-up/down arrows affect the top-left viewport instead of the bottom one.

brick version 0.1
vty-5.2.10 (as reported in my cabal sandbox's share/x86_64-osx-ghc-7.10.2 directory)

unsure where the output of cabal freeze goes.

`Eq` instances for Location and Cursor

I'm having to compare location quite often, and I'd like to avoid to define an orphan instance.
I can do the PR if you want (I believe ghc can derive Eq correctly anyway).
Any reason it's not there ?
(disclaimer, I'm fairly new to haskell)

Crash when emptying out lists

I can reproduce a crash from within vty with the message "cannot crop height to less than zero". I don't know if this is a vty or a brick problem, but I'll report it here:

Make a list with many entries, select one that wouldn't be initially visible and then empty the list (and set the selected element to Nothing).

Quickstart:

git clone https://github.com/rootzlevel/brick-reproduce
cd brick-reproduce
stack build --exec brick-reproduce

Then type any letter (e.g. f) to empty the list.

Here is the code:

{-# LANGUAGE OverloadedStrings #-}
module Main where

import           Brick
import           Brick.Widgets.List
import           Control.Lens ((&), (.~))
import           Control.Monad (void)
import qualified Data.Vector as V
import           Graphics.Vty

type AppState = List String

event :: AppState -> Event -> EventM (Next AppState)
event l e = case e of
  EvKey (KChar 'q') [] -> halt l
  EvKey _ _ -> continue $ l & listElementsL .~ V.empty
                            & listSelectedL .~ Nothing
  _ -> continue l

main :: IO ()
main = do

  let app = App { appDraw = \l -> [renderList l (const str)]
                , appChooseCursor = showFirstCursor
                , appHandleEvent = event
                , appAttrMap = const (attrMap defAttr [])
                , appLiftVtyEvent = id
                , appStartEvent = return
                }

      initList = list "list" (V.fromList [show x | x <- [1..500]]) 1
                   & listSelectedL .~ Just 400


  void $ defaultMain app initList

Scrolling a list widget that isn't at the top of the screen can result in an off-screen selected item

The program I'm working on has a list widget, but above the list widget are a fixed number of lines of plain-old text. The presence of those header lines seems to screw up the scrolling/visibility logic a bit.

Terminal version: iTerm2 2.1.1 and Terminal 2.5.3 (both on OS X Yosemite)
GHC version: 7.10.2
brick version: 0.2
vty version: 5.4.0
A simple repro program: https://github.com/ktvoelker/brick-demo

Steps to reproduce:

  1. Run the program
  2. Press the Down key until the last visible item is selected.
  3. Press the Down key one more time.
  4. An item is selected which is not visible.

Expected behavior:
4. The list scrolls and the item becomes visible.

Note that if you press Down a few more times, eventually the list does start scrolling in the right direction. But it never catches up, so the selected item is always off-screen. The size of this "offset" appears to be equal to the number of lines of header text, plus one.

I would be glad to work on fixing the bug myself, but I wanted to make sure that it actually is a bug, first.

Padding doesn't affect available width/height

Hi,

When a widget is padded, its available width and height don't seem to change. Is this intended? Presumably widgets need correct information.

Examples:

w :: Widget
w = Widget Fixed Fixed $ do
    c <- getContext
    render (str (show (availWidth c)))

-- shows "123"
main = simpleMain w

-- shows "          123"
main = simpleMain (padLeft (Pad 10) w)

Providing a frp interface

Looking at the App datatype, it seems to me that the interface could be expressed more concisely using some frp library such as reactive-banana or reflex. (And for users that otherwise already use some frp approach it needs a nasty layer between frp and the current state-passing interface.)

Has this been considered before? Do there exist any forks or other vty-reverse-deps that go in this direction?

Multi-line markup

Hi, not sure if this behavior is intended...

{-# LANGUAGE OverloadedStrings #-}

-- hi
-- there
main = simpleMain (txt "hi\nthere")

-- hi...
main = simpleMain (markup ("hi\nthere" @@ bg blue))

Multi-line markdown appears to just put an ellipsis where the first newline should go.

Banners

Hi,

Thanks for a really cool lib.

I'm interested in sorta doing full width banners or headers.
I mean full width of the viewport.

I want to do the equivalent of this

screen shot 2016-05-09 at 3 51 33 pm

and color the background.

I know I can do this manually with spaces, but looking for a way to do it automatically to the 'edge of view' or something like that.

(Apologizes in advance, i'm new to both Brick and Haskell, but having a lot of fun so far)

`halt` doesn't act like mzero

Hi, I've been playing around with brick a bit and I've noticed that halt doesn't behave like mzero. I'd like to write code that looks something like:

myHandler :: MyState -> Event -> EventM (Next MyState)
myHandler st evt = do
    when (evt `isKey` KEsc) $
        halt st

    ... further event handling ...

This is actually a somewhat larger problem for me than just when vs. if-then-else: I'd like to write composable, locally stateful event handlers using auto or similar, and step them forward in the top-level event handler them. However, currently I have no way of "inspecting" the return type of a handler (Next MyState) to see if indeed I should halt or continue.

I can easily work around this by defining my own ADT that encodes how to proceed, but it would essentially be almost identical to what already exists: either Continue or Halt.

Does this make sense? Thanks!

Support list paging operations

The list event handler needs to support paging operations. However, to do this, the event handling code needs to know about the viewport state from the most recent rendering pass. This is a blind spot in the current design but it can be done, and luckily this is a specific case of a more general problem of event handlers needing to consider rendering state in their decisions. Here's my plan:

  • Move EventM to Brick.Types
  • Make handleEvent run in EventM (This has the large added benefit of giving event handlers everywhere access to IO, which would make a lot of sense for use cases I can think of)
  • Make EventM a ReaderT over the recent viewport states
  • Add combinators to make lens-based operations cleaner since these changes would make handleEvent unwieldy; instead of
v <- handleEvent (st^.stuff) someEvent
continue $ st^.stuff .~ v

we'd have

continue =<< handleEventLensed st stuff someEvent

handleEventLensed :: (HandleEvent a) => s -> Lens' s a -> Event -> EventM s
handleEventLensed s func ev = do
  newVal <- handleEvent (s^.func) ev
  return $ s^.func .~ newVal
  • Add EventM functions for easy viewport state lookup
  • Add event handlers to list for paging operations using viewport state

(CC @simonmichael)

Space leak when app state accumulates?

Haskell memory leaks still confuse me, so this behavior might be expected from my code, but I’ve noticed that when application state is carried over between events, the heap blows up very fast. E. g., for a simple app which has state based on Text, and which appends 1k of text when each event fires, the heap size goes up very fast and memory will soon run out, even though only a linear amount of data is appended. If I change the txt resp. str widgets to only take as many lines and columns as available, the effect is reduced, but still present (so maybe the leak is with Vty, not Brick?).

This came up when I was trying to use a str widget to keep a log of incoming Vty events. After a few hundred lines the address space exceeded several GB.

I can reproduce this behavior with the following gist.

The following gives the heap profile for the gist after hammering away at the keys for a second.

graph

However, even though I should have library profiling enabled, neither the Vty or Brick modules appear in the graph, so it may well be it’s All My Fault™ after all. Maybe the issue makes more sense to you.

Thanks for making Brick!

trailing newline on rendered list elements disrupts layout

The right-padding issue I noticed on #7 was because my rendered list elements had a trailing newline. In this situation the row ends with an ellipsis, and an enclosing element's width is disrupted on that line. Eg instead of

|                        |
|    E                   |
|                        |

you see

|                        |
|    E…|
|                        |

Perhaps it should always strip trailing newlines, I expect it will be a common mistake.

key problems with Ctrl+arrow and Shift-tab in rxvt-unicode

Hello,

I use rxvt-unicode and running the brick demos I noticed

  • in edit demo tab moves to next edit but Shift-tab does not move to previous
  • in demos using Ctrl+arrow keys the part with Ctrl+arrow does not work

Using brick 0.4.1 on Debian Stretch

constraints: StateVar ==1.1.0.1,
adjunctions ==4.2.2,
array ==0.5.1.0,
base ==4.8.2.0,
base-orphans ==0.4.4,
bifunctors ==5,
binary ==0.7.5.0,
blaze-builder ==0.4.0.1,
bytestring ==0.10.6.0,
comonad ==4.2.7.2,
containers ==0.5.6.2,
contravariant ==1.3.3,
data-default ==0.5.3,
data-default-class ==0.0.1,
data-default-instances-base ==0.0.1,
data-default-instances-containers ==0.0.1,
data-default-instances-dlist ==0.0.1,
data-default-instances-old-locale ==0.0.1,
deepseq ==1.4.1.1,
directory ==1.2.2.0,
distributive ==0.4.4,
dlist ==0.7.1.2,
exceptions ==0.8.0.2,
filepath ==1.4.0.0,
free ==4.12.1,
ghc-prim ==0.4.0.0,
hashable ==1.2.3.3,
integer-gmp ==1.0.0.0,
kan-extensions ==4.2.3,
lens ==4.12.3,
mtl ==2.2.1,
old-locale ==1.0.0.7,
parallel ==3.2.0.6,
parsec ==3.1.9,
prelude-extras ==0.4.0.2,
pretty ==1.1.2.0,
primitive ==0.6.1.0,
profunctors ==5.1.1,
reflection ==2,
rts ==1.0,
semigroupoids ==5.0.0.4,
semigroups ==0.16.2.2,
stm ==2.4.4,
tagged ==0.8.2,
template-haskell ==2.10.0.0,
terminfo ==0.4.0.1,
text ==1.2.1.3,
text-zipper ==0.3.1,
time ==1.5.0.1,
transformers ==0.4.2.0,
transformers-compat ==0.4.0.4,
unix ==2.7.1.0,
unordered-containers ==0.2.5.1,
utf8-string ==1.0.1.1,
vector ==0.10.12.3,
void ==0.7.1,
vty ==5.3.1

Suggestion: Make Fixed widgets state their preferred size

To be precise, I'm suggesting that:

data Size = Fixed
    | Greedy

be changed to

data Size = Fixed Int
    | Greedy

with the semantics that Fixed n widgets take up n units of space, but will deal with less if they are given it, and Greedy widgets get given whatever is left over after space is allocated to Fixed widgets.

The benefits of the change are:

  • Forcing people to state/calculate the size of Fixed widgets, ensures that Fixed widgets actually have the correct semantics (this would have prevented #17, for example).
  • It makes boxRenderer much more modular, because it be implemented as:
    1. Calculate the amount of space to give each widget (which can be calculated from the amount of space available and the sizing of each widget)
    2. Render all the widgets
    3. Combine the results
  • Further to the previous point, implementing 2d tables becomes practical (the trick boxRenderer uses doesn't work in 2d)
  • It allows UI elements to degenerate in an orderly fashion when not given enough space. Currently the highest level boxRenderer just crops the resulting table. It would be more sensible if it instead rendered the sub-widgets with less space than requested.

The problems I can foresee are:

  • Every Fixed widget/combinator has to be changed. This is less bad than it seems. Every widget/combinator I found in the library can be implemented easily with the obvious Monoid and Ord instances for Size.
  • Programs that implement Fixed widgets directly are broken.

I'm happy to start implementing this, but I want to make sure you agree with basic idea first.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.