Merge pull request #149 from tigregalis/set-rich-text
Add `Buffer::set_rich_text` method
This commit is contained in:
commit
1eab951e27
2 changed files with 190 additions and 109 deletions
|
|
@ -1,8 +1,8 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use cosmic_text::{
|
||||
Action, Attrs, AttrsList, Buffer, BufferLine, Color, Edit, Editor, Family, FontSystem, Metrics,
|
||||
Shaping, Style, SwashCache, Weight,
|
||||
Action, Attrs, Buffer, Color, Edit, Editor, Family, FontSystem, Metrics, Shaping, Style,
|
||||
SwashCache, Weight,
|
||||
};
|
||||
use orbclient::{EventOption, Renderer, Window, WindowFlag};
|
||||
use std::{
|
||||
|
|
@ -36,8 +36,7 @@ fn main() {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let mut editor = Editor::new(Buffer::new(
|
||||
&mut font_system,
|
||||
let mut editor = Editor::new(Buffer::new_empty(
|
||||
Metrics::new(32.0, 44.0).scale(display_scale),
|
||||
));
|
||||
|
||||
|
|
@ -52,99 +51,75 @@ fn main() {
|
|||
let mono_attrs = attrs.family(Family::Monospace);
|
||||
let comic_attrs = attrs.family(Family::Name("Comic Neue"));
|
||||
|
||||
editor.buffer_mut().lines.clear();
|
||||
|
||||
let lines: &[&[(&str, Attrs)]] = &[
|
||||
&[
|
||||
("B", attrs.weight(Weight::BOLD)),
|
||||
("old ", attrs),
|
||||
("I", attrs.style(Style::Italic)),
|
||||
("talic ", attrs),
|
||||
("f", attrs),
|
||||
("i ", attrs),
|
||||
("f", attrs.weight(Weight::BOLD)),
|
||||
("i ", attrs),
|
||||
("f", attrs.style(Style::Italic)),
|
||||
("i ", attrs),
|
||||
],
|
||||
&[
|
||||
("Sans-Serif Normal ", attrs),
|
||||
("Sans-Serif Bold ", attrs.weight(Weight::BOLD)),
|
||||
("Sans-Serif Italic ", attrs.style(Style::Italic)),
|
||||
(
|
||||
"Sans-Serif Bold Italic",
|
||||
attrs.weight(Weight::BOLD).style(Style::Italic),
|
||||
),
|
||||
],
|
||||
&[
|
||||
("Serif Normal ", serif_attrs),
|
||||
("Serif Bold ", serif_attrs.weight(Weight::BOLD)),
|
||||
("Serif Italic ", serif_attrs.style(Style::Italic)),
|
||||
(
|
||||
"Serif Bold Italic",
|
||||
serif_attrs.weight(Weight::BOLD).style(Style::Italic),
|
||||
),
|
||||
],
|
||||
&[
|
||||
("Mono Normal ", mono_attrs),
|
||||
("Mono Bold ", mono_attrs.weight(Weight::BOLD)),
|
||||
("Mono Italic ", mono_attrs.style(Style::Italic)),
|
||||
(
|
||||
"Mono Bold Italic",
|
||||
mono_attrs.weight(Weight::BOLD).style(Style::Italic),
|
||||
),
|
||||
],
|
||||
&[
|
||||
("Comic Normal ", comic_attrs),
|
||||
("Comic Bold ", comic_attrs.weight(Weight::BOLD)),
|
||||
("Comic Italic ", comic_attrs.style(Style::Italic)),
|
||||
(
|
||||
"Comic Bold Italic",
|
||||
comic_attrs.weight(Weight::BOLD).style(Style::Italic),
|
||||
),
|
||||
],
|
||||
&[
|
||||
("R", attrs.color(Color::rgb(0xFF, 0x00, 0x00))),
|
||||
("A", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))),
|
||||
("I", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))),
|
||||
("N", attrs.color(Color::rgb(0x00, 0xFF, 0x00))),
|
||||
("B", attrs.color(Color::rgb(0x00, 0x00, 0xFF))),
|
||||
("O", attrs.color(Color::rgb(0x4B, 0x00, 0x82))),
|
||||
("W ", attrs.color(Color::rgb(0x94, 0x00, 0xD3))),
|
||||
("Red ", attrs.color(Color::rgb(0xFF, 0x00, 0x00))),
|
||||
("Orange ", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))),
|
||||
("Yellow ", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))),
|
||||
("Green ", attrs.color(Color::rgb(0x00, 0xFF, 0x00))),
|
||||
("Blue ", attrs.color(Color::rgb(0x00, 0x00, 0xFF))),
|
||||
("Indigo ", attrs.color(Color::rgb(0x4B, 0x00, 0x82))),
|
||||
("Violet ", attrs.color(Color::rgb(0x94, 0x00, 0xD3))),
|
||||
("U", attrs.color(Color::rgb(0x94, 0x00, 0xD3))),
|
||||
("N", attrs.color(Color::rgb(0x4B, 0x00, 0x82))),
|
||||
("I", attrs.color(Color::rgb(0x00, 0x00, 0xFF))),
|
||||
("C", attrs.color(Color::rgb(0x00, 0xFF, 0x00))),
|
||||
("O", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))),
|
||||
("R", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))),
|
||||
("N", attrs.color(Color::rgb(0xFF, 0x00, 0x00))),
|
||||
],
|
||||
&[(
|
||||
"生活,삶,जिंदगी 😀 FPS",
|
||||
let spans: &[(&str, Attrs)] = &[
|
||||
("B", attrs.weight(Weight::BOLD)),
|
||||
("old ", attrs),
|
||||
("I", attrs.style(Style::Italic)),
|
||||
("talic ", attrs),
|
||||
("f", attrs),
|
||||
("i ", attrs),
|
||||
("f", attrs.weight(Weight::BOLD)),
|
||||
("i ", attrs),
|
||||
("f", attrs.style(Style::Italic)),
|
||||
("i \n", attrs),
|
||||
("Sans-Serif Normal ", attrs),
|
||||
("Sans-Serif Bold ", attrs.weight(Weight::BOLD)),
|
||||
("Sans-Serif Italic ", attrs.style(Style::Italic)),
|
||||
(
|
||||
"Sans-Serif Bold Italic\n",
|
||||
attrs.weight(Weight::BOLD).style(Style::Italic),
|
||||
),
|
||||
("Serif Normal ", serif_attrs),
|
||||
("Serif Bold ", serif_attrs.weight(Weight::BOLD)),
|
||||
("Serif Italic ", serif_attrs.style(Style::Italic)),
|
||||
(
|
||||
"Serif Bold Italic\n",
|
||||
serif_attrs.weight(Weight::BOLD).style(Style::Italic),
|
||||
),
|
||||
("Mono Normal ", mono_attrs),
|
||||
("Mono Bold ", mono_attrs.weight(Weight::BOLD)),
|
||||
("Mono Italic ", mono_attrs.style(Style::Italic)),
|
||||
(
|
||||
"Mono Bold Italic\n",
|
||||
mono_attrs.weight(Weight::BOLD).style(Style::Italic),
|
||||
),
|
||||
("Comic Normal ", comic_attrs),
|
||||
("Comic Bold ", comic_attrs.weight(Weight::BOLD)),
|
||||
("Comic Italic ", comic_attrs.style(Style::Italic)),
|
||||
(
|
||||
"Comic Bold Italic\n",
|
||||
comic_attrs.weight(Weight::BOLD).style(Style::Italic),
|
||||
),
|
||||
("R", attrs.color(Color::rgb(0xFF, 0x00, 0x00))),
|
||||
("A", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))),
|
||||
("I", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))),
|
||||
("N", attrs.color(Color::rgb(0x00, 0xFF, 0x00))),
|
||||
("B", attrs.color(Color::rgb(0x00, 0x00, 0xFF))),
|
||||
("O", attrs.color(Color::rgb(0x4B, 0x00, 0x82))),
|
||||
("W ", attrs.color(Color::rgb(0x94, 0x00, 0xD3))),
|
||||
("Red ", attrs.color(Color::rgb(0xFF, 0x00, 0x00))),
|
||||
("Orange ", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))),
|
||||
("Yellow ", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))),
|
||||
("Green ", attrs.color(Color::rgb(0x00, 0xFF, 0x00))),
|
||||
("Blue ", attrs.color(Color::rgb(0x00, 0x00, 0xFF))),
|
||||
("Indigo ", attrs.color(Color::rgb(0x4B, 0x00, 0x82))),
|
||||
("Violet ", attrs.color(Color::rgb(0x94, 0x00, 0xD3))),
|
||||
("U", attrs.color(Color::rgb(0x94, 0x00, 0xD3))),
|
||||
("N", attrs.color(Color::rgb(0x4B, 0x00, 0x82))),
|
||||
("I", attrs.color(Color::rgb(0x00, 0x00, 0xFF))),
|
||||
("C", attrs.color(Color::rgb(0x00, 0xFF, 0x00))),
|
||||
("O", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))),
|
||||
("R", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))),
|
||||
("N\n", attrs.color(Color::rgb(0xFF, 0x00, 0x00))),
|
||||
(
|
||||
"生活,삶,जिंदगी 😀 FPS\n",
|
||||
attrs.color(Color::rgb(0xFF, 0x00, 0x00)),
|
||||
)],
|
||||
),
|
||||
];
|
||||
for &line in lines {
|
||||
let mut line_text = String::new();
|
||||
let mut attrs_list = AttrsList::new(attrs);
|
||||
for &(text, attrs) in line {
|
||||
let start = line_text.len();
|
||||
line_text.push_str(text);
|
||||
let end = line_text.len();
|
||||
attrs_list.add_span(start..end, attrs);
|
||||
}
|
||||
editor
|
||||
.buffer_mut()
|
||||
.lines
|
||||
.push(BufferLine::new(line_text, attrs_list, Shaping::Advanced));
|
||||
}
|
||||
|
||||
editor
|
||||
.buffer_mut()
|
||||
.set_rich_text(spans.iter().copied(), Shaping::Advanced);
|
||||
|
||||
let mut swash_cache = SwashCache::new();
|
||||
|
||||
|
|
|
|||
134
src/buffer.rs
134
src/buffer.rs
|
|
@ -618,21 +618,104 @@ impl Buffer {
|
|||
attrs: Attrs,
|
||||
shaping: Shaping,
|
||||
) {
|
||||
self.set_rich_text(font_system, [(text, attrs)], shaping);
|
||||
}
|
||||
|
||||
/// Set text of buffer, using an iterator of styled spans (pairs of text and attributes)
|
||||
///
|
||||
/// ```
|
||||
/// # use cosmic_text::{Attrs, Buffer, Family, FontSystem, Metrics, Shaping};
|
||||
/// # let mut font_system = FontSystem::new();
|
||||
/// let mut buffer = Buffer::new_empty(Metrics::new(32.0, 44.0));
|
||||
/// let attrs = Attrs::new().family(Family::Serif);
|
||||
/// buffer.set_rich_text(
|
||||
/// &mut font_system,
|
||||
/// [
|
||||
/// ("hello, ", attrs),
|
||||
/// ("cosmic\ntext", attrs.family(Family::Monospace)),
|
||||
/// ],
|
||||
/// Shaping::Advanced,
|
||||
/// );
|
||||
/// ```
|
||||
pub fn set_rich_text<'r, 's, I>(
|
||||
&mut self,
|
||||
font_system: &mut FontSystem,
|
||||
spans: I,
|
||||
shaping: Shaping,
|
||||
) where
|
||||
I: IntoIterator<Item = (&'s str, Attrs<'r>)>,
|
||||
{
|
||||
self.lines.clear();
|
||||
for line in BidiParagraphs::new(text) {
|
||||
self.lines.push(BufferLine::new(
|
||||
line.to_string(),
|
||||
AttrsList::new(attrs),
|
||||
shaping,
|
||||
));
|
||||
}
|
||||
// Make sure there is always one line
|
||||
if self.lines.is_empty() {
|
||||
self.lines.push(BufferLine::new(
|
||||
String::new(),
|
||||
AttrsList::new(attrs),
|
||||
shaping,
|
||||
));
|
||||
|
||||
let mut attrs_list = AttrsList::new(Attrs::new());
|
||||
let mut line_string = String::new();
|
||||
let mut end = 0;
|
||||
let (string, spans_data): (String, Vec<_>) = spans
|
||||
.into_iter()
|
||||
.map(|(s, attrs)| {
|
||||
let start = end;
|
||||
end += s.len();
|
||||
(s, (attrs, start..end))
|
||||
})
|
||||
.unzip();
|
||||
|
||||
let mut spans_iter = spans_data.into_iter();
|
||||
let mut maybe_span = spans_iter.next();
|
||||
|
||||
// split the string into lines, as ranges
|
||||
let string_start = string.as_ptr() as usize;
|
||||
let mut lines_iter = BidiParagraphs::new(&string).map(|line: &str| {
|
||||
let start = line.as_ptr() as usize - string_start;
|
||||
let end = start + line.len();
|
||||
start..end
|
||||
});
|
||||
let mut maybe_line = lines_iter.next();
|
||||
|
||||
loop {
|
||||
let (Some(line_range), Some((attrs, span_range))) = (&maybe_line, &maybe_span) else {
|
||||
// this is reached only if this text is empty
|
||||
self.lines.push(BufferLine::new(
|
||||
String::new(),
|
||||
AttrsList::new(Attrs::new()),
|
||||
shaping,
|
||||
));
|
||||
break;
|
||||
};
|
||||
|
||||
// start..end is the intersection of this line and this span
|
||||
let start = line_range.start.max(span_range.start);
|
||||
let end = line_range.end.min(span_range.end);
|
||||
if start < end {
|
||||
let text = &string[start..end];
|
||||
let text_start = line_string.len();
|
||||
line_string.push_str(text);
|
||||
let text_end = line_string.len();
|
||||
attrs_list.add_span(text_start..text_end, *attrs);
|
||||
}
|
||||
|
||||
// we know that at the end of a line,
|
||||
// span text's end index is always >= line text's end index
|
||||
// so if this span ends before this line ends,
|
||||
// there is another span in this line.
|
||||
// otherwise, we move on to the next line.
|
||||
if span_range.end < line_range.end {
|
||||
maybe_span = spans_iter.next();
|
||||
} else {
|
||||
maybe_line = lines_iter.next();
|
||||
if maybe_line.is_some() {
|
||||
// finalize this line and start a new line
|
||||
let prev_attrs_list =
|
||||
core::mem::replace(&mut attrs_list, AttrsList::new(Attrs::new()));
|
||||
let prev_line_string = core::mem::take(&mut line_string);
|
||||
let buffer_line = BufferLine::new(prev_line_string, prev_attrs_list, shaping);
|
||||
self.lines.push(buffer_line);
|
||||
} else {
|
||||
// finalize the final line
|
||||
let buffer_line = BufferLine::new(line_string, attrs_list, shaping);
|
||||
self.lines.push(buffer_line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.scroll = 0;
|
||||
|
|
@ -845,6 +928,29 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> {
|
|||
self.inner.set_text(self.font_system, text, attrs, shaping);
|
||||
}
|
||||
|
||||
/// Set text of buffer, using an iterator of styled spans (pairs of text and attributes)
|
||||
///
|
||||
/// ```
|
||||
/// # use cosmic_text::{Attrs, Buffer, Family, FontSystem, Metrics, Shaping};
|
||||
/// # let mut font_system = FontSystem::new();
|
||||
/// let mut buffer = Buffer::new_empty(Metrics::new(32.0, 44.0));
|
||||
/// let mut buffer = buffer.borrow_with(&mut font_system);
|
||||
/// let attrs = Attrs::new().family(Family::Serif);
|
||||
/// buffer.set_rich_text(
|
||||
/// [
|
||||
/// ("hello, ", attrs),
|
||||
/// ("cosmic\ntext", attrs.family(Family::Monospace)),
|
||||
/// ],
|
||||
/// Shaping::Advanced,
|
||||
/// );
|
||||
/// ```
|
||||
pub fn set_rich_text<'r, 's, I>(&mut self, spans: I, shaping: Shaping)
|
||||
where
|
||||
I: IntoIterator<Item = (&'s str, Attrs<'r>)>,
|
||||
{
|
||||
self.inner.set_rich_text(self.font_system, spans, shaping);
|
||||
}
|
||||
|
||||
/// Draw the buffer
|
||||
#[cfg(feature = "swash")]
|
||||
pub fn draw<F>(&mut self, cache: &mut crate::SwashCache, color: Color, f: F)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue