{"id":15713596,"url":"https://github.com/crystallabs/crysterm","last_synced_at":"2025-04-05T05:04:02.662Z","repository":{"id":45657001,"uuid":"217401234","full_name":"crystallabs/crysterm","owner":"crystallabs","description":"Console / terminal GUI toolkit for Crystal.","archived":false,"fork":false,"pushed_at":"2024-11-13T13:17:18.000Z","size":1321,"stargazers_count":135,"open_issues_count":15,"forks_count":10,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-29T04:04:40.447Z","etag":null,"topics":["cli","console-application","crystal","crystal-lang","terminal-based","terminal-graphics","tui"],"latest_commit_sha":null,"homepage":"","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crystallabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-24T21:50:18.000Z","updated_at":"2025-03-09T19:45:33.000Z","dependencies_parsed_at":"2025-01-26T09:10:54.064Z","dependency_job_id":"4ef4f24c-3872-4c8a-a76c-b5270c4cde40","html_url":"https://github.com/crystallabs/crysterm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crystallabs%2Fcrysterm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crystallabs%2Fcrysterm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crystallabs%2Fcrysterm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crystallabs%2Fcrysterm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crystallabs","download_url":"https://codeload.github.com/crystallabs/crysterm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289424,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","console-application","crystal","crystal-lang","terminal-based","terminal-graphics","tui"],"created_at":"2024-10-03T21:32:26.507Z","updated_at":"2025-04-05T05:04:02.641Z","avatar_url":"https://github.com/crystallabs.png","language":"Crystal","readme":"[![Linux CI](https://github.com/crystallabs/crysterm/workflows/Linux%20CI/badge.svg)](https://github.com/crystallabs/crysterm/actions?query=workflow%3A%22Linux+CI%22+event%3Apush+branch%3Amaster)\n[![Version](https://img.shields.io/github/tag/crystallabs/crysterm.svg?maxAge=360)](https://github.com/crystallabs/crysterm/releases/latest)\n[![License](https://img.shields.io/github/license/crystallabs/crysterm.svg)](https://github.com/crystallabs/crysterm/blob/master/LICENSE)\n\n# Crysterm\n\nCrysterm is a console/terminal toolkit for Crystal.\n\nAt the moment Crysterm follows closely the implementation and behavior of libraries that inspired it,\n[Blessed](https://github.com/chjj/blessed) and [Blessed-contrib](https://github.com/yaronn/blessed-contrib)\nfor Node.js. However, being implemented in Crystal (an OO language), it tries to use the language's\nbest practices, avoid bugs and problems found in Blessed, and also (especially in the future) incorporate\nmore aspects of [Qt](https://doc.qt.io/).\n\n## Trying out the examples\n\n```\ngit clone https://github.com/crystallabs/crysterm\ncd crysterm\nshards --ignore-crystal-version\n\nexport TERM=xterm-256color\n\ncrystal examples/hello.cr\ncrystal examples/hello2.cr\ncrystal examples/tech-demo.cr\n\n# And other examples from directories examples/, small-tests/, test/ and test-auto/.\n```\n\n## Using it as a module in your project\n\nAdd the dependency to `shard.yml`:\n\n```yaml\ndependencies:\n  crysterm:\n    github: crystallabs/crysterm\n    branch: master\n```\n\nThen add some code to your project, e.g.:\n\n```cr\nrequire \"crysterm\"\n\nalias C = Crysterm\n\nscreen = C::Screen.new\n\n# Optionally, you can include widgets in the current namespace:\n# include Crysterm::Widgets\n\nhello = C::Widget::Box.new \\\n  name: \"helloworld box\", # Symbolic name\n  top: \"center\",          # Can also be of format 10, \"50%\", or \"50%+-10\"\n  left: \"center\",         # Can also be of format 10, \"50%\", or \"50%+-10\"\n  width: 20,              # Can also be of format 10, \"50%\", or \"50%+-10\"\n  height: 5,              # Can also be of format 10, \"50%\", or \"50%+-10\"\n  content: \"{center}'Hello {bold}world{/bold}!'\\nPress q to quit.{/center}\",\n  parse_tags: true,       # Parse {} tags within content (default already is true)\n  style: C::Style.new(fg: \"yellow\", bg: \"blue\", border: true)\n\nscreen.append hello\n\n# When ctrl-q or q is pressed, exit.\n# (We can do this by listening for C::Event::KeyPress::CtrlQ specifically,\n# or for all C::Event::KeyPress and then checking the value of `e.char`.)\nscreen.on(C::Event::KeyPress) do |e|\n  if e.char == 'q' || e.key == Tput::Key::CtrlQ\n    screen.destroy\n    exit\n  end\nend\n\nscreen.exec\n```\n\n## Screenshots\n\nAnimated demo (examples/tech-demo.cr)\n\n![Crysterm Demo Video](https://raw.githubusercontent.com/crystallabs/crysterm/master/screenshots/2020-01-29-1.gif)\n\nLayout engine (showing inline/masonry layout, test/widget-layout.cr)\n\n![Crysterm Masonry Layout](https://raw.githubusercontent.com/crystallabs/crysterm/master/screenshots/layout.png)\n\nTransparency, color blending, and shadow (part of small-tests/shadow.cr)\n\n![Crysterm Color Blending](https://raw.githubusercontent.com/crystallabs/crysterm/master/screenshots/shadow.png)\n\n## Development\n\n### Introduction\n\nAs mentioned, Crysterm is inspired by Blessed, Blessed-contrib, and Qt.\n\nBlessed is a large, self-contained framework. Apart from implementing Blessed's core functionality, its authors have also\nimplemented all the necessary/prerequisite components, including an event model (a modified copy of an early Node.js\nEventEmitter), complete termcap/terminfo system (parsing, compilation, output, and input from terminal devices -- a complete\nalternative to ncurses), all types of mouse support, Unicode handling, color manipulation routines, etc.\nHowever, these implementations have been mixed with the rest of Blessed's source code, reducing the potential for their\nreuse.\n\nIn Crysterm, the equivalents of those components have been created as individual shards, making them available\nto the whole Crystal ecosystem. The event model has been implemented in\n[event_handler](https://github.com/crystallabs/event_handler), color routines in\n[term_colors](https://github.com/crystallabs/term_colors), terminal output in\n[tput.cr](https://github.com/crystallabs/tput.cr), GPM mouse in\n[gpm.cr](https://github.com/crystallabs/gpm.cr), and terminfo library in\n[unibilium.cr](https://github.com/crystallabs/unibilium.cr).\n\nUnibilium.cr represents Crystal's bindings for\na C terminfo library called [unibilium](https://github.com/neovim/unibilium/), now maintained by Neovim.\nThe package exists for a good number of operating systems and distributions, and one only needs the binary\nlibrary installed, not headers.\nThere is also a mostly working Crystal-native terminfo library available in\n[terminfo.cr](https://github.com/crystallabs/terminfo.cr) but, due to other priorities, trying to use that instead\nof unibilium is not planned. Both unibilium and native terminfo implementation for Crystal were initially\nimplemented by Benoit de Chezelles (@bew).)\n\nCrysterm closely follows Blessed, and copies of Blessed's comments have been included in Crysterm's sources for\neasier correlation and search between code, files, and features. A copy of Blessed's repository also exists in\n[docelic/blessed-clean](https://github.com/docelic/blessed-clean). It is a temporary repository in which\nfiles are deleted after their contents are reviewed and discarded or implemented in Crysterm.\n\nOverall, heavily basing the design on Blessed was a blessing and a curse. While Blessed demos are impressive,\nits code has many deficiencies and partially implemented features, and certain parts are not as obvious or\nsimple as they should be. This has slowed the development of Crysterm.\n\nHigh-level development plan for Crysterm looks as follows:\n\n1. Improving Crysterm itself (fixing bugs, replacing strings with better data types (enums, classes, etc.), and doing new development).\n1. Porting everything of value remaining in blessed-clean (most notably: reading terminfo command responses from terminal, mouse support, full unicode (graphemes), and a number of widgets)\n1. Porting over widgets \u0026 ideas from blessed-contrib\n1. Developing more line-oriented features. Currently Crysterm is suited for full-screen app development. It would be great if line-based features were added, and if then various small line-based utilities that exist as shards/apps for Crystal would be ported to become Crysterm's line- or screen-based widgets\n1. Adding features and principles from Qt\n\nThose are general guidelines. For smaller, more specific development/contribution tasks, see open issues, grep sources for \"TODO\", \"NOTE\", and \"XXX\",  see file `TODO`, and see general Crystal wishlist in file `CRYSTAL-WISHLIST`.\n\n### Event model\n\nEvent model is at the very core of Crysterm, implemented via [event_handler](https://github.com/crystallabs/event_handler).\n\nPlease refer to [event_handler](https://github.com/crystallabs/event_handler)'s documentation for all usage instructions.\n\nThe events used by Crysterm and its widgets are defined in `src/events.cr`.\n\n### Class Hierarchy\n\n1. Top-level class is `Screen`. It represents terminal used for `@input` and `@output`\n1. Each screen can have one or more `Widget`s, arranged appropriately to implement final apps\n\nWidgets can be added and positioned on the screen directly, but some widgets are particularly suitable for containing or arranging other/child widgets.\nMost notably this is the `Layout` widget which can auto-size and auto-position contained widgets in the form of a grid or inline (masonry-like) layout (`LayoutType::{Grid,Inline}`).\n\nThere are currently no widgets that would represent GUI windows like `QWindow` or `QMainWindow` in Qt\n(having title bar, menu bar, status bar, etc.), but implementing them is planned. (`Window`s too will inherit from `Widget`.)\n\nAll mentioned classes `include` [event_handler](https://github.com/crystallabs/event_handler) for event-based\nbehavior.\n\n### Positioning and Layouts\n\n![Crysterm Widget](https://raw.githubusercontent.com/crystallabs/crysterm/master/screenshots/widget.png)\n\nWidget positions and sizes work like in Blessed. They can be specified as numbers (e.g. 10), percentages (e.g. \"10%\"), both (e.g. \"10%+2\"), or specific keywords (\"center\" which has an effect of `50% - self.width_or_height//2`, or \"resizable\" which adjusts in runtime).\n\nThat model is simple and works quite OK, although it is not as developed as the model in Qt. For example, there is no way to shrink or grow widgets disproportionally when window is resized, and\nthere is no way to define maximum or minimum size. (Well, minimum size calculation does exist for resizable widgets, but only for trying to find the minimum size based on actual\ncontents, rather than programmer's wishes. (What we call \"resizable\" is suboptimally called \"shrink\" in Blessed because it can also grow.))\n\nThe interface for getting or setting values has been streamlined (further explanations below the table):\n\n| Spec | Absolute position | Relative position | Inner content offset |\n|------|----------|----------|-----------------------|\n| left / left= | aleft | rleft | ileft |\n| top / top= | atop | rtop | itop |\n| right / right= | aright | rright | iright |\n| bottom / bottom= | abottom | rbottom | ibottom |\n| width / width= | awidth | - | iwidth |\n| height / height= | aheight | - | iheight |\n\n\"Spec\" methods get or set the values exactly as the user specified them (e.g. \"50%+2\" or \"center\").\nAbsolute methods return computed values as integers in reference to screen.\nRelative methods return computed values as integers in reference to parent widget (or screen if parent is not defined).\nInner methods return offsets of content inside the widget (i.e. they report the sum of thickness of all widget's inner decorations like borders, padding, etc.)\n\nFor definitive guide on positioning, see `documentation/positioning.md`.\n\nSpeaking of layouts, the one layout engine currently existing, `Widget::Layout`, is equivalent to Blessed's. It can arrange widgets in a grid-like or masonry-like style.\nThere are no equivalents of Qt's `QBoxLayout`.\n\nThe positioning and layout code is very manageable; adding new Qt-like or other features is not a big task.\n(Whether various layouts would then still inherit from `Widget` or not (like they don't in Qt) is open for consideration.)\n\nNote: there are currently some differences in the exact types or combinations of mentioned value formats supported for `top`, `left`, `width`, `height`, and `align`. It would be\ngood if all these could be adjusted to accept the same flexible/unified specification, and if the list of supported specifications would even grow over time.\n(For example, one could want to pass a block or proc, in which case it'd be called to get the value.)\n\n### Rendering and Drawing\n\nScreens contain widgets. To make screens appear on display with all the expected contents and current state,\none calls `Screen#render`. This function calls `Widget#render` on each of direct children elements, which\nresults in the final/rendered state reflected in internal memory.\n\nAt the end of rendering, `Screen#draw` is automatically called which makes any changes in internal state appear on the\ndisplay. For efficiency, painter's algorithm is used, only changes (\"damage\") are rendered, and renderer\ncan optionally make use of CSR (change-scroll-region) and/or BCE (back-color-erase) optimizations\n(see `OptimizationFlag`, although some terminal emulators like `gnome-terminal` might not display them correctly\nso they are off by default).\n\nCalling `render` where ever appropriate is not a concern because there is code making sure that render\nruns at most once per unit of time (currently `property interval = 1/29`th of a second) and all accumulated changes are\nrendered in one pass.\n\nWhen state has been set up for the first time and the program is to start running the display, one\ngenerally calls `Screen#exec`. This renders the specified (or default) screen and starts running the\nprogram.\n\n### Text Attributes and Colors\n\nCrysterm inherits from Blessed a custom implementation/concept of \"tags\" in strings,\nsuch as `{light-blue-fg}Text in Light Blue{/light-blue-fg}`. Tags can be embedded in strings directly, applied\nfrom a Hash with `generate_tags`, or removed from a string with `strip_tags` or `clean_tags`.\nAny existing strings where \"{}\" should not be interpreted can be protected with `escape_tags`.\n\nThe supported tags are: `{center}`, `{left}`, and `{right}` for alignment,\n`{normal | default}`, `{bold}`, `{underline | underlined | ul}`, `{blink}`, `{inverse}`, and `{invisible}` for text attributes,\n`{COLOR-fg}` and `{COLOR-bg}` for colors,\nand `{/}` for closing all open tags.\n\nSupported COLOR names are:\n`default`,\n`black`,\n`blue`,\n`bright-black`,\n`bright-blue`,\n`bright-cyan`,\n`bright-gray`,\n`bright-green`,\n`bright-grey`,\n`bright-magenta`,\n`bright-red`,\n`bright-white`,\n`bright-yellow`,\n`cyan`,\n`gray`,\n`green`,\n`grey`,\n`light-black`,\n`light-blue`,\n`light-cyan`,\n`light-gray`,\n`light-green`,\n`light-grey`,\n`light-magenta`,\n`light-red`,\n`light-white`,\n`light-yellow`,\n`magenta`,\n`red`,\n`white`,\n`yellow`.\n\nIn addition to the above color names, one can also specify colors by color index (syntax: `{ID-...}`), or by RGB hex\nnotation using the 16M color palette (syntax `{#RRGGBB-...}`. 16M RGB is the recommended way to define colors, and\nCrysterm will automatically reduce them to 256, 16, 8, or 2 colors if/when needed, depending on terminal capabilities.\n\nOne could also define foreground and background colors and attributes by manually\nembedding the appropriate escape sequences into strings or using Crystal's `Colorize` module.\nCrysterm is interoperable with those approaches.\n\n### Styling\n\nEvery `Widget` has an attribute `style`, defining the colors and attributes to use during rendering.\nIf no style is explicitly defined, the default style is instantiated. Apart from styling the widget\nitself, each `Style` may have overriding style definitions for widget's possible subelements\n(border, scrollbar, track, bar, item, header, cell, label) and states (focus, blur, hover, selected).\n\nIf any of these subelements have more specific settings which define substantial behavior and not\njust visual aspects, they are defined as properties directly on the widget (e.g. `Widget#border`,\n`Widget#scrollbar`, etc.). These properties also serve as toggles that turn on or off respective\nelements.\n\nThe final goal (still to be implemented) is to be able to define one or a couple `Style` instances\nwhich would apply to, and style, all widgets. Additionally, these definitions would be\nserializable to YAML, enabling convenient theming.\n\n### Performance\n\nBy default, for development, frames-per-second value is displayed at the bottom of every Screen. When displaying FPS is enabled, Crysterm measures time needed to complete rendering and drawing cycles, and displays them as \"R/D/FPS\" (estimated renderings per second, drawings per second, and total/combined frames per second). Such as:\n\n```\nR/D/FPS: 761/191/153 (782/248/187)\n```\n\nThe first 3 values display the performance of the current frame, and the values in parentheses display the averages over 30 frames.\n\nBecause the rendering+drawing cycle happens up to `interval` times per second, the FPS value should stay above that value of it may indicate that frame skipping would occur.\n\n### Testing\n\nRun `crystal spec` as usual.\n\nMore specs need to be added.\n\nOne option for testing, currently not used, would be to support a way where all output (terminal\nsequences etc.) is written to an IO which is a file. Then simply the contents of that file are\ncompared with a known-good snapshot.\n\nThis would allow testing complete programs and a bunch of functionality at once, efficiently.\n\n### Documentation\n\nRun `crystal docs` as usual.\n\n### Notable Differences\n\nList of notable differences (hopefully improvements) compared to Blessed:\n\n- `Program` and `Display` have been removed\n- `Screen` is thus the top level component, and does not inherit from `Widget`\n- `Element` and `Node` have been consolidated into `Widget`\n- As such, `Screen` is not a top-level `parent` of any `Widget`; use `[@]screen` to get `Screen` or `parent_or_screen` for parent or screen\n- `tabc` (renamed to `tab_char`) and `tab_size` are properties of `Widget#style` instead of `Screen`\n- Screen `auto_padding : Bool` has been moved to Widget, and then later even removed (behaves like it is always enabled)\n- Screen itself can have a padding, same like Widgets\n- Event names have been changed from strings to classes, e.g. event `\"scroll\"` is `::Crysterm::Event::Scroll`\n- To remove ambiguity, events triggering at end of action have been adjusted to past tense (e.g. \"Rendered\" instead of \"Render\" is emitted at end of rendering)\n- `tags` alias for `parse_tags` option has been removed; use `parse_tags: true/false`. Default is true\n- All terminal-level stuff is in shard `Tput`, not `Crysterm`\n- `style` property has been consolidated; all style-related stuff is under widget's `@style : Style`\n- Widget property `shadow` is a bool, and default amount of transparency is `style.shadow_transparency = 0.5`\n- Style property `transparent` has been renamed to `transparency` and also accepts Float64, in addition to `true` which defaults to 0.5\n- In `Widget::ProgressBar`, the display of value is done using foreground color. This is different than Blessed and arguably more correct (Blessed uses background color)\n- In Crysterm, default border type is \"line\" (`BorderType::Line`). In Blessed it is \"bg\"\n- In Blessed, there is variable `ignore_dock_contrast`, which if set to true will cause borders to always be docked, or if set to false it will not dock borders of different colors. In Crysterm, this variable is defined as `@dock_contrast: DockContrast`, and `DockContrast` is an enum that can be `Ignore`, `DontDock`, or `Blend`. The first two behave like Blessed's true and false respectively, and `Blend` is a new option that blends (averages) colors and then performs docking.\n- In Crysterm, `attaching`/`detaching` Widgets is only applicable on Screens and it means setting/removing property `#screen` on the desired widget and its children (it does not have anything to do with widget parent hierarchy). Although in most cases these functions are not called directly but are invoked automatically when calling functions to set widgets' parents.\n- Widget property `valign` has been removed because property `align` is an enum (`Tput::AlignFlag`) and encodes both horizontal and vertical alignment choices in the same value\n- Widget property `noOverflow` is now `overflow : Overflow` with choices being `Ignore`, `ShrinkWidget`, `SkipWidget`, `StopRendering`, and `MoveWidget`\n- Widget methods `#\u003c\u003c` and `#\u003e\u003e` can be used for adding/removing children elements depending on argument type. E.g., `\u003c\u003c Widget` adds a Widget as a child of parent widget, and `\u003c\u003c Action` adds an Action into the widget's list of actions.\n- It is hard to remember whether screen size is kept in property `columns` or `cols`. So in Crysterm the `Screen`s dimensions are in `width` and `height`, and this is uniform with all `Widget`s which also have their size in `width` and `height`.\n- `shrinkBox` is `Rectangle` in Crysterm, and `_get_shrink` is `_get_minimal_rectangle`\n- User-specified Widget options left, top, right, bottom, width, height, and resizable exist directly on `Widget` in Crysterm, rather than on `Widget.position`. Also, to get actual numbers/values out, one now needs to explicitly use e.g. `aleft` (absolute left), `rleft` (relative left) or `ileft` (inner/content left). This removes all ambiguity and lack of straightforwardness in which value is being accessed\n- Widgets can have shadow on any of the 4 sides, instead of always being drawn on the right and bottom\n- Renamed properties in Crysterm: `widget.noFill` is `!style.fill?`, `autoFocus` is `focus_on_click?`, `wrap` is `wrap_content?`, `hidden` is `!visible?`\n- Implementation of `clean_tags` and `strip_tags` has been switched, for better/more-intuitive naming in Crystal\n- The following variables were renamed to more intuitive variants:\n  - `_listened_keys` = `_listening_keys?`\n  - `lock_keys` = `!propagate_keys?`\n  - `ignore_locked` = `always_propagate`\n\nList of current bugs / quirks in Crysterm, in no particular order:\n\n- It is likely that Crysterm's API interface and general usability could be improved in many places. Fortunately those are easy improvements and/or suggestions that can be made by early users and adopters\n- Items need to be added to `Widget::List` explicitly, after list creation (option `items: [...]` to `List.new` isn't available at the moment)\n- `Widget::Layout` needs explicit width and height (e.g. \"100%\"). It seems this isn't needed in Blessed\n- `Widget::TextArea` lacks many features (deficiency inherited from Blessed)\n- Scrollbar on a widget can be enabled with `scrollbar: true`. Styling for the scrollbar column is taken from `@style.track` and for the scrollbar character from `@style.scrollbar`. This is inherited from Blessed and unintuitive. `style.scrollbar` should be the column, and `style.track` (or other name) should be the scroll position indicator.\n- Some parts of code are marked with \"D O:\" or \"E O:\". These mean \"Disabled Originally\" and \"Enabled Originally\", indicating whether respective parts of code were disabled or enabled \"originally\" (in Blessed sources). Those marked with \"D O:\" do not need any work unless they were part of unfinished improvements in Blessed, in which case they probably should be developed/enhanced in Crysterm.\n- In some places functions like '#setX' have been renamed to '#x=' while in others they weren't.\n- There is no `Image` widget which can display an image in ANSI or an overlay. Use one or the other (`Widget::Image::Ansi` or `Widget::Image::Overlay`) explicitly. (`Image::Ansi` does not exist yet.)\n\nIf you notice any problems or have any suggestions, please submit an issue.\n\n## Thanks\n\n* All the fine folks on Libera.Chat IRC channel #crystal-lang and on Crystal's Gitter channel https://gitter.im/crystal-lang/crystal\n\n## Other projects\n\nList of interesting or similar projects in no particular order:\n\nTerminal-related:\n\n- https://github.com/Papierkorb/fancyline - Readline-esque library with fancy features\n- https://github.com/r00ster91/lime - Library for drawing graphics on the console screen\n- https://github.com/andrewsuzuki/termbox-crystal - Bindings, wrapper, and utilities for termbox\n\nColors-related:\n\n- https://crystal-lang.org/api/master/Colorize.html - Crystal's built-in module Colorize\n- https://github.com/veelenga/rainbow-spec - Rainbow spec formatter for Crystal\n- https://github.com/watzon/cor - Make working with colors in Crystal fun!\n- https://github.com/icyleaf/terminal - Terminal output styling\n- https://github.com/ndudnicz/selenite - Color representation conversion methods (rgb, hsv, hsl, ...) for Crystal\n- https://github.com/jaydorsey/colorls-cr - Crystal toy app for colorizing LS output\n\nEvent-related:\n\n- https://github.com/crystallabs/event_handler - Event model used by Crysterm\n- https://github.com/Papierkorb/cute - Event-centric pub/sub model for objects inspired by the Qt framework\n- https://github.com/hugoabonizio/event_emitter.cr - Idiomatic asynchronous event-driven architecture\n\nMisc:\n\n- https://github.com/Papierkorb/toka - Type-safe, object-oriented option parser\n- https://github.com/eliobr/termspinner - Simple terminal spinner\n- https://github.com/epoch/tallboy - Draw ascii character tables in the terminal\n- https://github.com/teuffel/ascii_chart - Lightweight console ASCII line charts\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrystallabs%2Fcrysterm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrystallabs%2Fcrysterm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrystallabs%2Fcrysterm/lists"}