Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Strange symbols instead of colored text #800

Closed
xairaven opened this issue Sep 16, 2024 · 7 comments
Closed

[BUG] Strange symbols instead of colored text #800

xairaven opened this issue Sep 16, 2024 · 7 comments
Labels

Comments

@xairaven
Copy link
Contributor

xairaven commented Sep 16, 2024

Describe the bug
Hi! I am writing my own version of the project github.com/kognise/arpchat for educational purposes. I encountered an issue where strange symbols appear next to the colored text in my project. By colored text, I mean text styled using methods from crossterm::style::stylize::Stylize, for example, "some text".dark_grey().to_string(). You can see what I mean in the screenshot. I will provide some code snippets for reproduction, but it would be easier to clone the project I mentioned above and run it.

An interesting detail I noticed is that if I set the Cursive version to 0.20.0, everything works as expected. But starting from version 0.21.0, it breaks. I can’t simply use version 0.20.0 because it only works with that original project, where I tested the transitions between versions (it works on nightly old Rust). My project is written using the stable Rust version 1.81, and for some reason, it doesn’t compile with Cursive versions earlier than 0.21.1.

I apologize if I missed something, and this is my mistake and not a bug. I’d be happy to collaborate.

To Reproduce

use cursive::backends::crossterm::crossterm::style::Stylize;
use cursive::views::{LinearLayout, NamedView, TextView};
use cursive::Cursive;
ui::cursive_extension::append_txt(
                siv,
                "chat_area",
                "some_text".dark_grey().to_string(),
            );

Another file:

use cursive::traits::Nameable;
use cursive::utils::markup::StyledString;
use cursive::views::{LinearLayout, TextView};
use cursive::Cursive;

/// Append a new `TextView` to the `LinearLayout` with the provided parent name.
pub fn append_txt<S>(siv: &mut Cursive, parent_id: &str, content: S)
where
    S: Into<StyledString>,
{
    siv.call_on_name(parent_id, |parent: &mut LinearLayout| {
        parent.add_child(TextView::new(content));
    });
}

Expected behavior
Colored text instead of strange symbols.

Screenshots
Cursive version 0.21 (changed just the version in Cargo.toml):
image

Cursive version 0.20:
image

Environment

  • OS: Windows 10 22H2
  • Backend used: I don't know. I create cursive object with cursive::default(). If I use use feature crossterm-backend, result stays the same.
  • Current locale (run locale in a terminal): System Locale: en-us;English (United States); Input Locale: en-us;English (United States)
  • Cursive version (from crates.io, from git, ...): 0.21.1
@xairaven xairaven added the bug label Sep 16, 2024
@xairaven
Copy link
Contributor Author

Update: I just managed to compile my project using this line in Cargo.toml:

cursive = { version = "0.20.0", default-features = false, features = ["toml", "crossterm-backend"]}

Yes, as expected, everything works on version 0.20. However, if I use version 0.21.1 like this:

cursive = { version = "0.21.1", default-features = false, features = ["toml", "crossterm-backend"]}

Or this:

cursive = { version = "0.21.1", features = ["toml"]}

I see strange characters instead of colors, meaning the situation is the same to what I described earlier. You can check the screenshots to understand what I mean.

@gyscos
Copy link
Owner

gyscos commented Sep 16, 2024

Hi, and thanks for the report!

The main issue is that "some_text".dark_grey().to_string() returns some text with "ansi" markup, which cursive doesn't understand by default. Cursive 0.21 brought some performance optimization (an output buffer cell grid) which makes this even more visible - but even with 0.20 you would run into various issues.

Note that cursive does support styled text with StyledString, just not a regular String with ansi codes inside.

You can parse ansi text into a StyledString: https://docs.rs/cursive/latest/cursive/utils/markup/ansi/fn.parse.html
But it's a bit roundabout to use crossterm to generate an ansi string, just to parse it back.

You could instead directly build the cursive-native StyledString, for example with StyledString::single_span if you only need a single style for the entire string.

There is also cursup, a simple markup language: https://docs.rs/cursive/latest/cursive/utils/markup/cursup/index.html

@xairaven
Copy link
Contributor Author

Thank you so much for your response! I used the ansi::parse() function, and everything works. Sorry for bothering you, I couldn't find the information myself, although there were similar examples in the documentation🤦‍♂️ I think the issue is resolved, so it can be closed. However, I also created a pull request with an example of my problem. If you find it relevant, I'd be happy to help someone else who might encounter the same issue when upgrading to the new version and misses the ansi example. My example directly addresses the issue I faced: #801

@xairaven
Copy link
Contributor Author

@gyscos, By the way, is there a way to remove ANSI codes from a string and get plain text without any styling? For example, I have "some text".dark_grey().to_string(). Can I get plain text from this text without ANSI characters? I tried this:

let ansi_text = "some text".dark_grey().to_string();
let parsed = SpannedString::<Style>::plain(ansi_text);
format!("{}", parsed.source()).as_str();

but it didn’t work. Sorry if this is a silly question.

@gyscos
Copy link
Owner

gyscos commented Sep 18, 2024

You have a couple of ways to get that:

  • Iterate on the spans, and accumulate the span text content, ignoring the styles.
  • Use compact or canonicalize, which rebuilds the source to only include visible text (no markup), and then get the source. Note that this technically modifies the StyledString, and requires mutable access.
fn iterate_on_spans(styled: &cursive::utils::markup::StyledString) -> String {
    styled.spans().map(|span| span.content).collect()
}

fn canonicalize(styled: &mut cursive::utils::markup::StyledString) -> String {
    styled.canonicalize();
    styled.source().to_string()
}

fn main() {
    let mut styled = cursive::utils::markup::cursup::parse("/blue{This} /white{is} /red{sparta}!");

    println!("`{}`", iterate_on_spans(&styled));
    println!("`{}`", canonicalize(&mut styled));
}

@xairaven
Copy link
Contributor Author

Thank you so much again for your response! Everything worked out, and it's all functioning perfectly. I really enjoyed working with Cursive; it's a very convenient library. I’ve finished my first project with it - xArpChat.

Additionally, I completed the pull request with the example of colored text (#801). I gathered all your answers and included links to the documentation for the methods used.

I'm closing the issue. Thank you so much again for your help! If you find my pull request appropriate, I would be very happy to become a contributor to Cursive. Also, I apologize if any of my words sounded rude, I don't know English well.

@gyscos
Copy link
Owner

gyscos commented Sep 20, 2024

I'm glad you found what you were looking for! And good luck on xArpChat! Feel free to ask question if you need support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants