GithubHelp home page GithubHelp logo

gyscos / cursive Goto Github PK

View Code? Open in Web Editor NEW
4.1K 40.0 236.0 3.13 MB

A Text User Interface library for the Rust programming language

License: MIT License

Rust 99.99% Nix 0.01%
ncurses rust tui terminal

cursive's Introduction

Cursive

crates.io Rust MIT licensed Gitter chat

Cursive is a TUI (Text User Interface) library for rust. It uses ncurses by default, but other backends are available.

It allows you to build rich user interfaces for terminal applications.

It is designed to be safe and easy to use:

[dependencies]
cursive = "0.20"

Or to use the latest git version:

[dependencies]
cursive = { git = "https://github.com/gyscos/cursive" }

(You will also need ncurses installed.)

use cursive::views::{Dialog, TextView};

fn main() {
    // Creates the cursive root - required for every application.
    let mut siv = cursive::default();

    // Creates a dialog with a single "Quit" button
    siv.add_layer(Dialog::around(TextView::new("Hello Dialog!"))
                         .title("Cursive")
                         .button("Quit", |s| s.quit()));

    // Starts the event loop.
    siv.run();
}

Cursive dialog example

Check out the other examples to get these results, and more:

lorem.rs example menubar.rs example select.rs example mines example theme_manual.rs example syntect example

(Colors may depend on your terminal configuration.)

Tutorials

These tutorials may help you get started with cursive:

Third-party views

Here are a few crates implementing new views for you to use:

Showcases

Here are some cool applications using cursive:

  • RustyChat: Chat client made using Rust and Cursive.
  • checkline: Checkbox line picker from stdin to stdout.
  • clock-cli: A clock with stopwatch and countdown timer functionalities.
  • fui: Add CLI & form interface to your program.
  • game2048-rs: a tui game2048 using Rust and cursive.
  • git-branchless: Branchless workflow for Git.
  • grin-tui: Minimal implementation of the MimbleWimble protocol.
  • kakikun: A paint and ASCII art application for the terminal.
  • launchk: Manage launchd agents and daemons on macOS.
  • mythra: CLI to search for music.
  • ncspot: Cross-platform ncurses Spotify client.
  • rbmenu-tui: A TUI for bookmark management.
  • retris: A simple implementation of the classic tetris game.
  • ripasso: A simple password manager written in Rust.
  • rusty-man: Browse rustdoc documentation.
  • saci-rs: Simple API Client Interface.
  • so: A terminal interface for Stack Overflow.
  • sudoku-tui: Play sudoku on the command line.
  • tap: An audio player for the terminal with fuzzy finder.
  • wiki-tui: A simple and easy to use Wikipedia Text User Interface

Goals

  • Ease of use. Simple apps should be simple. Complex apps should be manageable.
  • Linux TTY Compatibility. Colors may suffer, and UTF-8 may be too much, but most features must work properly on a Linux TTY.
  • Flexibility. This library should be able to handle simple UI scripts, complex real-time applications, or even games.
    • In particular, it tries to have enough features to recreate these kind of tools:

Compatibility

First off, terminals are messy. A small set of features is standard, but beyond that, almost every terminal has its own implementation.

Output

  • Colors: the basic 8-colors palette should be broadly supported. User-defined colors is not supported in the raw linux TTY, but should work in most terminals, although it's still kinda experimental.
  • UTF-8: Currently Cursive really expects a UTF-8 locale. It may eventually get patched to support window borders on other locales, but it's not a priority. There is initial support for wide characters. RTL support is planned, but still very early.

Input

  • The key_codes example can be a useful tool to see how the library reacts to various key presses.
  • Keep in mind that if the terminal has shortcuts registered, they probably won't be transmitted to the app.
  • UTF-8 input should work fine in a unicode-enabled terminal emulator, but raw linux TTY may be more capricious.

Alternatives

See also ratatui - and a small comparison page.

cursive's People

Contributors

agavrilov avatar alexanderkjall avatar alexargoai avatar ameobea avatar arxanas avatar chrisvest avatar cubetastic33 avatar danobi avatar dermetfan avatar geniecs avatar gyscos avatar hasezoey avatar hcpl avatar igbc avatar jwuensche avatar matthiasbeyer avatar mehmooda avatar nabijaczleweli avatar ngg avatar quininer avatar riey avatar robbystk avatar robinkrahl avatar sanbox-irl avatar tianyishi2001 avatar timdubbins avatar timonpost avatar trolley813 avatar untitaker avatar vmedea 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cursive's Issues

Better input compatibility table

The current one is wrong in some places. Also, alt+key input has started (and will eventually be complete), so the array definitely needs some improvement.

Maybe doesn't need to be on the Readme though; an interactive standalone page (or one page per category) could be a better choice.

And then there'll be the task of filling this table. Not sure how to automate this... :S

Support outset-like borders

Menuconfig has a "outset" on the borders, using two colors to make a 3D impression.
Having this option in the theme would be nice.

Support right-to-left languages

Some languages like Japanese and Chinese can write right-to-left (and/or top to bottom), but are fine with the usual left-to-right orientation.
Other languages like Arabic simply must be written right-to-left (I think?), so we may need some support for those.
Low priority for now, as I know next to nothing about how RTL languages are usually used on terminals.

Use event channel

Instead of polling.

And select on both the event and the callback channels.
Maybe also on a third refresh channel?

(One goal is to eliminate the need for a refresh rate in most cases, by sending a refresh signal instead.)

Add LinearLayout

Or LinearView or whatever: a list of views aligned in one direction.

TODO: how to compute the size for each child? Especially when they are fluid (like TextViews).

Support word-wrapping for asian languages

The main issue is resolved, the remaining point is word-wrapping for asian languages. More specifically, line break can happen between many characters, not just at whitespaces. This would avoid breaking lines at an early lonely whitespace, wasting space on the line.

Old issue:
Some CJK characters (and maybe others?) use 2 columns in the terminal.
Cursive currently assumes every codepoint is 1 column wide.
First step is to use grapheme instead of codepoint when computing width.
Until then asian languages will not work well.

Split `view` internals and `View`s collection

The view module is currently used for two different purposes:

  • The internal components required to build a View
  • A list of Views ready to use

These two use-cases are fairly separate, and would be better served with two different modules. Finding good names is the trickiest part...

Support themes

Define at runtime some colors and characters used for special effects (border, highlight, shadow, ...).
Probably provide a default theme that looks like the blue interface used by classic ncurses dialog applications.

Add a menubar

Not necessarily a View in itself, but at least something that can be added to the root Cursive.

Notes:

  • Should it be global, or per screen?
  • Should it be available when a popup is visible?
  • When opening a window (ex: options), it should make sure the window does not already exist (or raise it? Sounds dangerous if a popup from Options is shown...)
  • Togglable auto-hide (reserves 1 row when off), configurable "show" button (ex: F10).
    • When auto-hidden and with no "show" button, acts as if no menubar was present.
  • Must be able to draw the "popup" menus outside of its regular bounds, so not a traditional View...

Add `recommended size` to Views

I wanted to keep the base View trait as simple as possible, but it looks like we'll need a second layout function.
The big issue is being able to properly layout "fluid" views like TextViews. They have an ideal size (longest line * number of lines), but can squeeze into smaller sizes if required (they will then scroll).
Buttons, on the other hand, have quite definitive limits.
A linear layout made of buttons and text views, therefore, will have a mixed state, with an absolute minimum size it can fit into, and an ideal size to take when conditions are favorable.

Currently, the get_min_size confusingly applies the recommended size.

The proposed solution is to have 2 methods:

  • A true get_min_size, which returns the absolute minimum size required not to panic.
    • This likely won't depend on the size constraints.
  • A get_recommended_size, which depends on the constraints (with a small fixed width, a TextView will prefer to be taller).

During layout, view groups will try to give their children their ideal size. If that's impossible, they will look for the minimum sizes, and split the rest. The idea is to know where we can cut corners - in the current situation, it doesn't seem possible.

Use case: the linear example must provide scrolling with low-height windows.

Load layout from configuration file

It may be easier to define some complex layouts in external files rather than build it manually in the source code.

Would need to define a layout representation (xml? json? yaml? qml?)...
We have a toml parser already to read themes, but toml doesn't seem like a good fit for this.

Using a language with an existing layout connotation (like qml or html) may look weird if we have to limit/change the actually usable elements.

Only clear the screen when required

Cursive currently clears the screen on every event.

However, it really only needs to be cleared:

  • When removing views
  • When resizing the window

Permit precise view placement in a stackview

When adding a new layer to a stackView, it sometimes needs to be precisely placed (select popups for instance, see #36).

An solution would to be edit the StackView and give each layer a position parameter. It could be centered (the current default), or an absolute location, or a position relative to the previous layer.

It needs to be careful when the view would not fit at the asked location. elinks pushes the window if possible, then simply resize it when it already takes all the space available.

Add a direction to `take_focus`

Currently, views just "take" the focus, without any direction information.

This means a linear view will always start with the first element in focus, even if the selection comes from an element to the left/bottom (like a dialog button).

Adding a direction parameter to take_focus would allow views to change their behavior appropriately.

Cursive prints garbage on non-utf8 locale

Currently cursive uses utf8 to print dialog borders. This means when running with non-unicode locale, it prints garbage.
Ncurses should be able to print the correct characters no matter the locale (nmtui for instance works with any locale). Not sure how to do it though...

Add ScrollView

layouts the child with unknown height (or width) and only draw a subset of it.

Add prelude

Instead of importing lots of submodules, maybe offer a prelude to easily import most important stuff.

Add popup-select views

Especially useful in ListView, a one-line SelectView that shows a MenuPopup would be a nice addition.

Investigate alternative backend

Ncurses is nice, but is pretty much terrible.

Intersting alternatives currently include rustty and termion.

First step would be to remove references to ncurses types from the public API (there's not a lot left).

Make printer crop

Printer currently does not use its size to crop calls to print methods.
If we don't trust the view to color inside the lines, we may want to enforce it (and ignore commands outside of bounds).
This might make scroll view easier too.

Add unit tests for layout/get_min_size/draw methods

Some views need some minimal space to display properly. It's usually just a few cells, but as views include other views, it adds up. And while it's rarely an issue in regular use, when resizing a view, it can happen, if only temporarily.

Currently, it often results in a panic from usize overflows.

Rather than crashing, displaying an empty view would be a minimal thing to do. Showing an error message (like "Screen size too small" or something) would be even better.

Better unicode input support

EditView currently ignores any non-ascii input.
Investigate how ncurses handle non-ascii input, and make EditView work with that.

Support dialogs with buttons on the right

Currently dialogs have their buttons on the bottom as a row.
Having buttons on the right as a column would be more convenient in some situations, for instance when selecting an item from a vertical list.

Make themes more production-friendly

Loading from a file is nice during development to experiment with the look without having to recompile, but to deploy an application, it's easier to include the theme in the binary.

Adding a method to load the theme directly from a string (rather than a filename as is currently the case) would allow users to include_str! their theme during release.

Ideally, switching from parsing the file at runtime and including it at compile time would require as little modifications as possible...

Also, modifying the current theme should also be easier (an in-app "options" menu should be able to change some properties).

Draw boxes manually

Box-drawing characters are part of UTF-8, so that's easy to do on modern terminals, but linux TTY still rely mostly on ASCII, and needs a different treatment.
ncurses has a nice system (with ACS_* characters) to print box characters whatever the backend, but it's a bit buggy, so moving to a home-made solution would be easier (especially if we later move to termion).

After some experiments, it seems the unicode values (for instance E2 94 8C for โ”Œ) work on a linux TTY, even when using LANG=C... so let's go for it!

Composable UI

I watch development of this crate rather interested for some weeks now and I think this could be the crate I want to use to implement a ncurses-UI for my imag project.

The point is: imag is a program (or rather collection of programs) that gets composed from components, and I want to continue it this way also when implementing a ncurses UI for it.

So for example if I implement a CUI for imag-diary I still want to be able to re-use the code I've written for this UI to integrate the UI into a more general UI.

Think of this:

  • Each crate (imag-diary, imag-notes, imag-wiki, etc.) has its own ncurses UI, implemented in the respective libimag* crate
  • I can reuse the code from the libimag* crates to write a all-in-one curses UI

Is this possible with Cursive? If yes, what has to be done, API wise on my side, to approach this?


My guesses:

  • One has to create types which implement cursive::View (which are basically the UI for the respective crate. So one has one type and an implementation of cursive::View for it for libimagentryview, one for libimagdiary, one for libimagfoobar and so on)
  • One can then use these to implement a per-crate UI or
  • One can use these to integrate them into a more general UI

Am I right with this?


If the upper things are not possible or complicated to approach with the current API design of Cursive, you are welcome to use this as feature-request'ish issue! ๐Ÿ˜„

Add examples to documentation

Examples currently live nicely hidden in the examples directory, but it's now their time to shine.

Let's have examples in sub-modules or in the specific Views themselves.

Build failure OSX 10.11

Hi, I'm attempting to build and run the hello example. Apparently, OSX 10.11 seems to have run into some conflicts with the installed ncurses lib. I've installed the ncurses dependency via homebrew tap, resulting in the following error:

~/tmp/rust/ncurse(master โœ—) cargo build -v
       Fresh libc v0.2.13
       Fresh rustc-serialize v0.3.19
       Fresh ncurses v5.80.0
       Fresh toml v0.1.30
       Fresh cursive v0.0.2
   Compiling ncurse v0.1.0 (file:///Users/ag/tmp/rust/ncurse)
     Running `rustc src/main.rs --crate-name main --crate-type bin -g --out-dir /Users/ag/tmp/rust/ncurse/target/debug --emit=dep-info,link -L dependency=/Users/ag/tmp/rust/ncurse/target/debug -L dependency=/Users/ag/tmp/rust/ncurse/target/debug/deps --extern cursive=/Users/ag/tmp/rust/ncurse/target/debug/deps/libcursive-19b294b0688ff15d.rlib`
error: linking with `cc` failed: exit code: 1
note: "cc" "-m64" "-L" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "/Users/ag/tmp/rust/ncurse/target/debug/main.0.o" "-o" "/Users/ag/tmp/rust/ncurse/target/debug/main" "-Wl,-dead_strip" "-nodefaultlibs" "-L" "/Users/ag/tmp/rust/ncurse/target/debug" "-L" "/Users/ag/tmp/rust/ncurse/target/debug/deps" "-L" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "/Users/ag/tmp/rust/ncurse/target/debug/deps/libcursive-19b294b0688ff15d.rlib" "/Users/ag/tmp/rust/ncurse/target/debug/deps/libtoml-cd71fbce840828ea.rlib" "/Users/ag/tmp/rust/ncurse/target/debug/deps/libncurses-28f717993e75ef1e.rlib" "/Users/ag/tmp/rust/ncurse/target/debug/deps/liblibc-a70a3ae81492eede.rlib" "/Users/ag/tmp/rust/ncurse/target/debug/deps/librustc_serialize-3bc953984ed46e7f.rlib" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libstd-d16b8f0e.rlib" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcollections-d16b8f0e.rlib" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librustc_unicode-d16b8f0e.rlib" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librand-d16b8f0e.rlib" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liballoc-d16b8f0e.rlib" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liballoc_jemalloc-d16b8f0e.rlib" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liblibc-d16b8f0e.rlib" "/Users/ag/.multirust/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcore-d16b8f0e.rlib" "-l" "ncursesw" "-l" "System" "-l" "pthread" "-l" "c" "-l" "m" "-l" "compiler-rt"
note: ld: library not found for -lncursesw
clang: error: linker command failed with exit code 1 (use -v to see invocation)

error: aborting due to previous error
error: Could not compile `ncurse`.

Caused by:
  Process didn't exit successfully: `rustc src/main.rs --crate-name main --crate-type bin -g --out-dir /Users/ag/tmp/rust/ncurse/target/debug --emit=dep-info,link -L dependency=/Users/ag/tmp/rust/ncurse/target/debug -L dependency=/Users/ag/tmp/rust/ncurse/target/debug/deps --extern cursive=/Users/ag/tmp/rust/ncurse/target/debug/deps/libcursive-19b294b0688ff15d.rlib` (exit code: 101)  

UPDATE: I uninstalled brew ncurse recipe, re-installed ncurses via macports and upgraded readline package. I get the same build failure output, displayed above. Oddly, macports lists ncurses dev branch v6.0, yet the build output seems to point v.5.8. Any suggestions on how to resolve?

Text View

If one can insert text in the text view (is this the right name?), it would be cool to have a possibility to get the mutable string from that object. Or even better: pass a function to the object which gets called with a context object (user defined) and the mutable string, so one can implement a editor backend to call for example vim with the text.

Might worth a try to submit a PR for me... I will have a look at this later, maybe I can come up with something.

Add view selector

Currently a view can only be selected from the root with a ViewPath.
Adding selectors (like css-selectors) and ViewWrappers with an ID would make it easier to find a view from the code.
Even more important if the layout is loaded from a file, when we don't have easy access to the ViewPaths.

Add multi-line edit text

Probably use a rope or something.

It will need to integrate some of TextView's row-computing features, so some re-organization is in order.

Progress bar

Would be nice to have something like a progress bar which can be updated from a thread or something...

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.