iced icon indicating copy to clipboard operation
iced copied to clipboard

Add basic support for text highlighting

Open Pixelstormer opened this issue 2 years ago • 3 comments

Adds support for changing the background colour of various parts of text, to enable things like highlighting search results, marking outstanding regions of text, etc.

You could achieve a similar effect before this PR by splitting your text into multiple Text structs and nesting the parts you want to highlight in a Container with a background colour set, but this is not a viable solution as doing so interferes with text layouting, as demonstrated in the below videos.

Text highlighting using the aforementioned containers-based method (Notice how the text fidgets around as the highlighting changes):

/* Snip */
let splitter = &self.highlight_input_value;
                            
let mut row = Row::new();
let mut split = s.split(splitter);
                            
if let Some(first) = split.next() {
    row = row.push(Text::new(first));
}
                            
for s in split {
    row = row
        .push(
            Container::new(Text::new(splitter))
                .style(ContainerStyle::red()),
        )
        .push(Text::new(s));
}
/* Snip */

https://user-images.githubusercontent.com/28542452/156685350-6d1837b7-fea1-4eaa-b445-6bd1c55b9818.mp4

Text highlighting using the highlight method introduced by this PR:

/* Snip */
let mut text = Text::new(s);
for (index, _) in s.match_indices(&self.highlight_input_value) {
    text = text.highlight(
        index,
        index + self.highlight_input_value.len(),
        Color::from_rgb8(0xff, 0xc0, 0xcb),
    );
}
/* Snip */

https://user-images.githubusercontent.com/28542452/156685426-c456722b-18e9-433f-9bb2-368e67aebad4.mp4

Pixelstormer avatar Mar 04 '22 02:03 Pixelstormer

I think this is related to #156.

We are not only interested in highlighthing support, but also changing color, font, size, and other text properties without affecting layout.

hecrj avatar Mar 06 '22 05:03 hecrj

It's worth considering what the API for this should look like. If Iced ever gets full rich text support, this will likely be integrated with that, but until then this will need its own API.

Currently the API accepts grapheme indexes; graphemes are the most intuitive way to deal with partitioning rendered text, and indeed, there is no intuitive answer as to what a highlight should look like if it were to be specified by byte or char index instead, and ended up cutting a grapheme in half.

The issue with this is the std library provides no way to observe strings via their graphemes (Iced itself uses this crate), instead dealing with bytes and chars . This is a problem as I think it would be reasonable to say that for most use cases of text highlighting, the region of text to highlight would be calculated programmatically, and thus would likely be represented (on the user's end) as bytes or chars, rather than graphemes (Unless the user specifically uses a grapheme processing crate).

The API could be changed to accept bytes or char`s, but that would either require extra input sanitisation to handle inputs that don't conform to a grapheme boundary (Do we silently ignore, return an error or panic?), or somehow interpreting what highlights would look like if they start or end in the middle of a grapheme.

On the other hand, keeping the API as-is would pass these burdens on to the user, requiring them to convert their data into grapheme indexes. We could expose helper methods to aid with this, but doing so could be scope creep.

I am certainly not acquainted enough with Iced's architecture and design philosophies to make any kind of informed decision on my own (Not only about API but the other topics mentioned in my above comments), so I'm willing to delegate to the opinion of someone more familiar with Iced.

Pixelstormer avatar Mar 12 '22 00:03 Pixelstormer

@Pixelstormer What do you think of this crate? https://crates.io/crates/unicode-segmentation

The .unicode_words() method seems good enough in the case of highlighting, don't you think?

cryptoquick avatar Jul 08 '22 09:07 cryptoquick

I think there is still a lot of discussion that needs to happen before we can start thinking about code here.

I have some text rendering improvements coming soon in the pipeline. I am aware I am the main bottleneck here! Once those improvements land, we can review this approach and evaluate if it's suitable or whether we can reuse any parts or not.

hecrj avatar Oct 03 '22 18:10 hecrj