GithubHelp home page GithubHelp logo

console's Introduction

console

Build Status Crates.io License rustc 1.56.0 Documentation

console is a library for Rust that provides access to various terminal features so you can build nicer looking command line interfaces. It comes with various tools and utilities for working with Terminals and formatting text.

Best paired with other libraries in the family:

Terminal Access

The terminal is abstracted through the console::Term type. It can either directly provide access to the connected terminal or by buffering up commands. A buffered terminal will however not be completely buffered on windows where cursor movements are currently directly passed through.

Example usage:

use std::thread;
use std::time::Duration;

use console::Term;

let term = Term::stdout();
term.write_line("Hello World!")?;
thread::sleep(Duration::from_millis(2000));
term.clear_line()?;

Colors and Styles

console automaticaly detects when to use colors based on the tty flag. It also provides higher level wrappers for styling text and other things that can be displayed with the style function and utility types.

Example usage:

use console::style;

println!("This is {} neat", style("quite").cyan());

You can also store styles and apply them to text later:

use console::Style;

let cyan = Style::new().cyan();
println!("This is {} neat", cyan.apply_to("quite"));

Working with ANSI Codes

The crate provides the function strip_ansi_codes to remove ANSI codes from a string as well as measure_text_width to calculate the width of a string as it would be displayed by the terminal. Both of those together are useful for more complex formatting.

Unicode Width Support

By default this crate depends on the unicode-width crate to calculate the width of terminal characters. If you do not need this you can disable the unicode-width feature which will cut down on dependencies.

License: MIT

console's People

Contributors

adminxvii avatar archina avatar atanunq avatar cosmichorrordev avatar dalance avatar danieleades avatar dependabot[bot] avatar devinr528 avatar grunweg avatar hugorahlen avatar jonas-schievink avatar joshka avatar kyllingene avatar lebensterben avatar lingman avatar mitsuhiko avatar mosal avatar obsgolem avatar phlosioneer avatar pksunkara avatar pnmtjonahen avatar r-darwish avatar repi avatar richrandall avatar shadoka avatar shenek avatar spenserblack avatar stuhood avatar ttys3 avatar waywardmonkeys 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

console's Issues

Get terminal size from /dev/tty directly

In #1 it shouldn't be necessary for the user to know whether to ask for the size of stdout or stderr. The program is running in some tty and we want the size of that, whatever stdout and stderr happen to be doing.

Publish is_term undeprecation to crates.io

f61351b was merged to master last month, closing #86, but was never published to crates.io. Builds of downstream crates like indicatif are still printing deprecation warnings and the method still appears as deprecated in docs.rs documentation.

warning: use of deprecated associated function `console::Term::is_term`: Use features().is_attended() instead
   --> /git/tmp/indicatif/src/progress.rs:138:65
    |
138 |             ProgressDrawTargetKind::Term(ref term, ..) => !term.is_term(),
    |                                                                 ^^^^^^^
    |
    = note: `#[warn(deprecated)]` on by default

Screenshot from 2021-03-06 22-17-42

Is there a to_string method?

Is there something like a StyledObject.to_string() method?

for something like format!("{} hi", style("some string").dim()) - because "format!" will "throw" format argument must be a string literal

Term clear_screen panics on windows 10

Just to be sure this should work on windows 10 in cmd.exe?

let t = Term::stdout();
t.write_line("hello")?;
t.clear_screen()?;

I get a panic caused by multiplication overflow from windows_term.rs line 120 in my case x=120, y=9001. If this is a bug on windows and not just me I can give you a bit more info.

Thanks!

Order of width/height in Term::stdout().size() has changed

The order of width/height in the tuple output of Term::stdout().size() has changed from 0.10.0 to 0.10.1. I assume that this was not intentional. Otherwise, 0.10.1 breaks semver.

Edit: The docs for size_checked explicitly say "the terminal size in rows and columns", so I guess rows should indeed be first.

The order is still "wrong" in 0.11.

see: sharkdp/bat#955

Long-term, using a simple struct instead of a tuple would be a good idea IMO.

style! or console::format! macro

I might be nice to have a fancy style! (or console::format!) macro to replace format! usage.

Example

This is how I could make a progress string now.

let progress = 100.0 / 3.0;
let elapsed = Duration::from_secs(66);

let progress = format!(
    "{:.1}% in {:?}",
    style(progress).bold(),
    style(elapsed).green().italic(),
);

The macro could work something like:

let progress = 100.0 / 3.0;
let elapsed = Duration::from_secs(66);

let progress = style!("{:.1.bold}% {:?.green.italic}", progress, elapsed);

Or with argument capture:

let progress = 100.0 / 3.0;
let elapsed = Duration::from_secs(66);

let progress = console::format!("{progress:.1.bold}% {elapsed:?.green.italic}");

clicolors-control?

The documentation refers to clicolors-control a few times but that doesn't appear to be a dependency of this project. Am I misunderstanding something or is this a small mistake in the docs?

Piping data via STDIN into executable makes text prompts not work

Issue
As soon as I populate the STDIN pipe to my program with any data, the text prompts won't work properly.

Context
I have a binary that does text processing (https://github.com/replicadse/complate).
In the past, the configuration for the template was loaded via a configuration file. I have added a feature with which one should be able to pipe the configuration string directly into the print command.

Behaviour

dialoguer::Input::new().allow_empty(false).with_prompt("some text").interact()

When specifying allow_empty(false), the terminal flickers and shows weird behaviour. I can not enter text nor can I do anything else than Ctrl+C exit.
When specifying allow_empty(true), the data result string is empty.

References
Here you can see me reading the data from STDIN:
https://github.com/replicadse/complate/pull/10/files#diff-c5354523dab7ee14c84278715c952cb7e302af46f5c8372b94375b36f003b93eR138
Here you can see me using dialoguer:
https://github.com/replicadse/complate/blob/master/src/render/mod.rs#L174

Make more use of `Read` and `Write`

Creating a Term from Read and Write was added in #34 (merged #93 ) which is pretty cool 🎉
I am using that mechanism to write a TestTerminal that buffers calls to Write internally and has prepared content for Read.

My code uses term.read_line() though, which to my surprise uses stdin() directly.
I was expecting that to go through Read.

Is that something that could be adjusted? I can probably try and submit a PR?

Capture key modifiers

Say I want to capture Shift / Alt / Ctrl

Is there any way of doing that with this library?

Is there any way of knowing if a key is currently pressed?
it seems like the lib only captures keydown event and not keyup so we can't even know if it was released or not?

emoji goodness for linux

Any chance of getting some Emoji goodness on linux? I know it's patchy but it is there. Something along the lines of:

#[cfg(target_os = "linux")]
lazy_static! {
    static ref is_lang_utf8 : bool = {
        match ::std::env::var("LANG") {
            Ok(lang) => lang.to_uppercase().ends_with("UTF-8"),
            _ => false
        }
    };
}
pub fn wants_emoji() -> bool {
    cfg!(target_os = "macos") || ( cfg!(target_os = "linux") && *is_lang_utf8 )
}

User input fails on the Run window when executed within IntelliJ IDEA on Windows 10

When any user input is requested of the user via the Run window within IntelliJ IDEA, the user's input is not recognized (this is on a Windows machine). This is not true for the "integrated terminal" within IntelliJ IDEA.

This is a bit of a pain, because the default "Run" command and the "Run Anything" commands execute in the Run window.

read_key() does not recognize backspace

Hi,

on Win10 read_key() does not return Key::Backspace when pressing backspace.
Just running standard Win10-Console, no Git-Bash, PS or anything else.
Following code should loop as long as I am only pressing backspace, but terminates nonetheless:

Small gist

console-version: 0.9.2
rust-version: 1.38.0

An unfortunate side effect is that read_line_initial_text does not delete the last char but just sets the cursor one to the left.

[Windows] Not a terminal error when shift key is pressed

When reading a line from the terminal, pressing the shift key results in an error { kind: NotConnected, error: "Not a terminal" } on Windows. It seems to happen with both Powershell and Command Prompt

To Reproduce

(In Windows)

git clone https://github.com/mitsuhiko/console.git
cargo run --example term
# press shift key on the To edit prompt

VS Code Terminal + clear_last_lines

Hi. I'm attempting to write an interactive console app for a toy project and am using console.

The problem comes from calling term.clear_last_lines(n) where n is larger than the number of visible lines. It produces an underflow exception. Curiously neither standalone powershell.exe nor cmd.exe have this issue. So I'm not sure what's special about VSCode.

A workaround for the exception is change move_cursor_up.rs move_cursor_up from csbi.dwCursorPosition.Y as usize - n to (csbi.dwCursorPosition.Y as usize).saturating_sub(n). But this doesn't actually clear the requested number of lines so it's not ideal.

Colors are not reset in Windows when using Term::write

use console::{style, Color, Term};
use std::io::Write;

fn main() {
    let mut term = Term::stdout();
    term.write_fmt(format_args!(
        "{}",
        style("Grass green. I hate that color!\n").fg(Color::Green)
    ))
    .unwrap();
    term.write_line("Shouldn't be green");
}

The above program works as expected in Windows when used with console v0.10.1. However, with console v0.11.3 the second line is also green.

Create a Term from arbitrary Read and Write pair

Currently, a Term can only be created from stdin and either stdout or stderr. This covers the most common case, but is rather inflexible.

The issue I'm running into is that I can't mock user interaction with my program (which uses dialoguer) in a test case, because there's no way to create a Term that's connected to mock I/O streams.

Another possible use case is interacting with a user through a socket. For instance, a Rust program might contain an embedded SSH server and interact with users that way.

Please consider allowing the creation of Terms connected to arbitrary Read and Write implementations, or at least arbitrary file descriptors/handles.

Odd `clear_line` behavior

Code:

use std::io::{self, Write};
use console::Term;

fn main() -> io::Result<()> {
    let mut term = Term::buffered_stdout();
    term.write_line("Hello, World")?;
    term.clear_line()?;
    term.write(b"zzzzz")?;
    term.flush()
}

Result:

zzzzzHello, World

I get this same result with the following consoles in Windows 10:

  • Git Bash
  • cmd
  • urxvt (via Cygwin)

Escape key is not recognized as correct Enum and not returned immediately

There are two (possibly related issues here)

When I press the escape key when running term.read_key(), nothing is returned until another (anything will do) key is pressed.

Regardless of what the second key pressed is, the value returned is not Key::Escape but Key::Char('\u{2b}')

I was digging into the source code and noticed this message that could point to where the issue might lie?

https://github.com/mitsuhiko/console/blob/9aab753cc811b3fed824c85c0e17b34042dd5ab9/src/unix_term.rs#L92

mintty read_key fails with "Incorrect function"

use console::Term;
fn main() {
    let term = Term::stdout();
    let result = term.read_key();
    match result {
        Ok(k) => println!("Key: {:?}", k),
        Err(e) => println!("Error: {:?}", e),
    };
}

Running this code using mintty. Ran this code using msys and mingw. When running though the integrated terminal in visual studio code the code passes. When running it on mintty it fails with the line

Error: Os { code: 1, kind: Other, message: "Incorrect function." }

illumos support

I have had dcuddeback/termios-rs#21 open on termios-rs for 7 months and it doesn't look there has been any activity for almost a year on that repo. It's been a pain to deal with anything on illumos/solaris that uses console due to the need to point Cargo.toml at my custom version. Would you be opposed to a PR that changes the unix dependency on termios-rs to point to a fork of that repo with my change for illumos/solaris and leave all other unix's pointing at the official repo. One example of where dealing with this has been painful is when building "bat".

Term::read_line_initial_text() inconsistent with Term::read_line() regarding terminating newline

Term::read_line() allows the delimiting newline to be printed to the terminal, even though it is omitted from the returned String. This is the same as the documented behaviour of BufRead::read_line(), which Term::read_line() ends up calling.

The implementation of Term::read_line_initial_text() is not consistent with this. In this case, the newline is not printed to the terminal.

use console::Term;

fn main() {

    let term = Term::stderr();

    println!("Enter ten lines. The final five will have initial text");
    for _ in 1..6 {
        term.read_line().unwrap();
    }

    for _ in 6..11 {
        term.read_line_initial_text("Inital text ").unwrap();
    }
}

After I run the above and enter the numbers 1 to 10, my terminal looks like this:

Enter ten lines. The final five will have initial text
1
2
3
4
5
Inital text 6Inital text 7Inital text 8Inital text 9Inital text 10$

Undeprecate is_term

@pksunkara can we undeprecate is_term? It's such a common operation and now you need to use a much more complex API to use it.

New lines do not start from column 0

Hi.
Thanks for creating this crate.

Can you please tell me if I am doing something wrong or there is a bug?
I made a minimal repro at https://gitlab.com/yerke/repro_tui_bug
The problem is that new lines do not start from column 0.
Here is the example of the output I see on Mac:

$ ./run.sh 
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/repro_tui_bug`
Hello, world!
[2019-10-27T03:52:26Z DEBUG repro_tui_bug] Hello from main thread 1
                                                                   [2019-10-27T03:52:26Z DEBUG repro_tui_bug] Hello from main thread 2
                                                      [2019-10-27T03:52:33Z DEBUG repro_tui_bug] Please press any button
[src/main.rs:12] key = Ok(
    Char(
        'f',
    ),
)
[2019-10-27T03:52:33Z DEBUG repro_tui_bug] Hello from spawned thread 1
[2019-10-27T03:52:33Z DEBUG repro_tui_bug] Hello from spawned thread 2
$ 

Thanks.

Is there a way to disable emojis?

Forgive me if it's documented and I couldn't find it. I'm trying to write a CLI that prints emojis for some commands, but I know that there are people (me included) who probably won't want emojis, especially if we're redirecting the output to a text file or something. Is there support for a settiing that disables all emojis?

I currently have a --no-emojis flag that I use, and my commands check for that, but that isn't the most elegant of solutions since I have multiple layers of subcommands.

Perhaps one type of behaviour would be to fall back to the alternate text when the emojis are disabled?

Key::Enter not working on PowerShell

Hi,

I'm currently using Rust to write a console game and when I do:

let key = term.read_key().ok();
    match key.unwrap() {
        Key::Char('q') => std::process::exit(0),
        Key::Enter => if *turn == 1 {
                *turn = 2; 
        } else {
            *turn = 1;
        },
        
        _ => ()
    }

Option is key Enter is never called. Neither with normal Enter or Right Enter.

I'm using Windows 10 with PowerShell (I know Windows bleh...)

Allow virtual non-FD terminals

Following up on #34, allow using not just arbitrary FDs, but arbitrary virtual streams by making Term a trait.

Use case: displaying TUI to clients on an SSH server.

No emoji support inside of WSL Ubuntu 18.04

According to the source code, it checks if the LANG env ends with UTF-8. Mine does (C.UTF-8). It still prints out false when I run console::Term::stdout().features().wants_emoji().

console::Term::stdout().features().family() reports UnixTerm. console::Term::stdout().features().is_attended() returns true as well.

Not sure if this matters:

println!("{:#?}", term_intance.features());
Emoji: TermFeatures(
    Term {
        inner: TermInner {
            target: Stdout,
            buffer: None,
        },
        is_msys_tty: false,
        is_tty: true,
    },
)

`show_cursor` also clears the screen

The show_cursor command does way more than just show the cursor ([?25h). I think this should be changed just to show the cursor, and nothing else, so it matches the behavior of its counterpart, hide_cursor.

Also, see #25

[Feature Reqest] Get cursor position

I'm running into an issue where '\r' is being mapped to '\n' when running a program in urxvt via Cygwin. My idea to work around this is to just set the cursor position to column 0 of the current line. However, I can't get the current line with console.

Ideal usage:

let mut term = console::Term::stdout();
let (_, y) = term.get_cursor_pos()?;
term.move_cursor_to(0, y)?;

Possible Alternatives:

  1. Add move_cursor_left and move_cursor_right. This complements the already existing functions move_cursor_up and move_cursor_down. Although in the use case I'm talking about, there's still extra work the caller has to do if they want to move "all the way" left or right.
  2. For convenience add, move_cursor_to_start and move_cursor_to_end (or something similar). Not sure on the naming here, but the idea would be to have functions that move the cursor either to the very beginning of the current line or the very end.

Styling doesn't nest well

I tried to do this:

style(format!("No mod named {} found", style(name).bold())).yellow()

I expected this to print out a fully yellow line, but instead I got:

image

Remove native windows console handling

Newer crates now leave a completely broken windows experience behind compared to earlier versions because instead of turning on ANSI code handling on the windows term it tries to emulate this. This has caused a bunch of very bad regressions (#69, #83).

This will require putting clicolors-control back in see #91.

Support custom colours

Would it be possible to add a means to define new colours, for use with terminals that support a broader range of them?

Text input yields Key::Unknown on windows_term using alt

This relates to: console-rs/dialoguer#116

Dialoguer listens to Key::Unknown events to cancel the UserInput[1]. This works fine on Linux. On Windows however, windows_term generates Key::Unknown events for special characters.

On my English keyboard layout I can use the ¿ (alt+/) character to create these events. This results in the whole text_input crashing for dialoguer.

Originally I planned on just adding Key::Alt to the list. However winapi also seems to identify the key wrong (the events comes in as 0x12) which would reference the menu key[2]. Which should be incorrect.

I could map the events to Key::Composite just to mark that a key composition event is taking place or use Key::Alt and comment the location to add a fix if/when winapi is fixed/changed.

Term::size is broken on Windows

Since the update to the terminal-size crate, Term::size and Term::size_checked are broken on Windows due to eminence/terminal-size#18

Term::size_checked returns None on interactive terminals. It returns (1, 1) if no terminal is attached to STDOUT.

Also, note that there is another change in behavior (which is probably good): After eminence/terminal-size#18 has been fixed, terminal-size reports a terminal size which is larger by one in both height and width (https://github.com/eminence/terminal-size/blob/e9a708e15a5e582aad03855e40d1f41b6b01c5f0/src/windows.rs#L38-L39). The returned size is correct. The value returned by console 0.10 and before was too small.

Please provide example of reading a char

Googling how to read a char (w/o return) a few sites say to use this crate, and some provide a defective example. Maybe they're wrong and this crate doesn't do that, but it appears to have a read_char() method. How would a person accomplish this?

Revert back to clicolors-control

We removed the clicolors-control dependency at one point last year and switched to a separate crate. This now made a mess out of this because now the color handling no longer agrees.

Commit and followups that should be reverted: 176f99f

There are now some changes that might want to be added to clicolors-control. I still need to verify.

Add support for show and hide cursor?

Would a pull request to add the ability to hide/show the cursor be welcome, something like this?

impl Term {
	...
	fn cursor_hide(&mut self) -> io::Result<()> {
        let esc = "\u{001B}";
        let hide = format!("{}[?25l", esc);
        self.write(hide.as_bytes())?;
        Ok(())
    }

    fn cursor_show(&mut self) -> io::Result<()> {
        let esc = "\u{001B}";
        let show = format!("{}[0H{}[0J{}[?25h", esc, esc, esc);
        self.write(show.as_bytes())?;
        Ok(())
    }
}

Style renders incorrectly before and after running command

This bug is two-fold. I assume it's the same bug, which just manifests itself in two different ways, depending on the terminal used.

  1. Using Git Bash on Windows 10. Then using .dim() does not have any effect. However, after running a command e.g. git diff using std::process::Command, then .dim() has an effect.
  2. On the other hand, using CMD or PowerShell, then after running the command, then the ANSI codes appear literally in the output.

The command being executed seem to be important, as changing the command to e.g. cargo --version or even git --version. Then 2. does not happen. However, then .dim() isn't "fixed" either.

Git Bash

Notice the third .dim() styled Foo is rendered the same as the first unstyled Foo.

Without Changes:

dim

With Changes:

dim2

CMD

Renders the same with and without changes, and renders the same in PowerShell.

dim-cmd

Minimal, Reproducible Example

// rustc 1.41.0 (5e1a79984 2020-01-27)
// cargo 1.41.0 (626f0f40e 2019-12-03)

use std::process::Command;

// console = "0.9.2"
use console::style;

fn main() {
    println!("Foo {} Baz", "Bar");
    println!("Foo {} Baz", style("Bar").cyan());
    println!("Foo {} Baz", style("Bar").dim());
    println!("Foo {} Baz", style("Bar").red());
    println!();

    // Renders incorrectly if git diff is executed
    Command::new("git").arg("diff").status().unwrap();

    // Has not effect
    // Command::new("cargo").arg("--version").status().unwrap();
    // Command::new("git").arg("--version").status().unwrap();

    println!("Foo {} Baz", "Bar");
    println!("Foo {} Baz", style("Bar").cyan());
    println!("Foo {} Baz", style("Bar").dim());
    println!("Foo {} Baz", style("Bar").red());
    println!();
}

Buffering is ignored when using io::Write

This caused me a lot of confusion: when clearing and rewriting the screen, the clear commands were actually executed after the writes that were issued later, since they were buffered and the writes were not. For now, the only workaround is to use Term::write_line and the undocumented Term::write_str.

Additionally, flushing through io::Write is a no-op, while Term::flush actually flushes buffered terminals.

Is there any reason why the io::Write implementation cannot use buffering that I'm missing here?

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.