Skip to content

Commit 8664857

Browse files
authored
Merge pull request #684 from kas-gui/push-omsookkxrmsq
Fix text-selection foreground color
2 parents 82df4e6 + 904f0ba commit 8664857

File tree

6 files changed

+86
-109
lines changed

6 files changed

+86
-109
lines changed

crates/kas-core/src/text/format.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ pub use kas_text::format::FontToken;
2121
pub struct Color(NonZeroU32);
2222

2323
impl Default for Color {
24-
/// Use a theme-defined color (automatic)
2524
fn default() -> Self {
2625
Self::DEFAULT
2726
}
2827
}
2928

3029
impl Color {
31-
/// Use the default theme-defined color
30+
/// Use the theme-defined text color
3231
///
3332
/// As a foreground color, this maps to [`ColorsLinear::text`] or
3433
/// [`ColorsLinear::text_invert`] depending on the background.
@@ -37,7 +36,7 @@ impl Color {
3736
pub const DEFAULT: Self =
3837
Color(NonZeroU32::new(u32::from_ne_bytes(Rgba8Srgb::rgba(1, 0, 0, 0).0)).unwrap());
3938

40-
/// Use the text-selection color
39+
/// Use the theme-defined text selection color
4140
///
4241
/// As a foreground color this is identical to [`Self::DEFAULT`].
4342
///
@@ -82,11 +81,9 @@ impl Color {
8281

8382
/// Resolve as (foreground) text color
8483
#[inline]
85-
pub fn resolve_foreground(self, theme: &ColorsLinear, bg: Option<Rgba>) -> Rgba {
84+
pub fn resolve_foreground(self, theme: &ColorsLinear) -> Rgba {
8685
if let Some(col) = self.as_rgba() {
8786
col
88-
} else if let Some(bg) = bg {
89-
theme.text_over(bg)
9087
} else {
9188
theme.text
9289
}
@@ -117,6 +114,20 @@ pub struct Colors {
117114
pub background: Option<Color>,
118115
}
119116

117+
impl Colors {
118+
/// Resolve as (foreground) text color
119+
#[inline]
120+
pub fn resolve_foreground(self, theme: &ColorsLinear) -> Rgba {
121+
if let Some(col) = self.foreground.as_rgba() {
122+
col
123+
} else if let Some(bg) = self.background {
124+
theme.text_over(bg.resolve_background(theme))
125+
} else {
126+
theme.text
127+
}
128+
}
129+
}
130+
120131
/// Decoration types
121132
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
122133
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]

crates/kas-core/src/text/raster.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ impl State {
554554
.map(|e| e.1 == Default::default())
555555
.unwrap_or(true)
556556
{
557-
let col = Color::default().resolve_foreground(theme, None);
557+
let col = Color::default().resolve_foreground(theme);
558558
self.text_with_color(allocator, queue, pass, pos, bb, text, col);
559559
return;
560560
}
@@ -575,7 +575,7 @@ impl State {
575575
}
576576
};
577577

578-
let col = token.foreground.resolve_foreground(theme, None);
578+
let col = token.resolve_foreground(theme);
579579
queue.push_sprite(pass, glyph.position.into(), bb, col, sprite);
580580
};
581581

@@ -634,7 +634,7 @@ impl State {
634634
};
635635

636636
// Known limitation: this cannot depend on the background color.
637-
let col = token.color.resolve_foreground(theme, None);
637+
let col = token.color.resolve_foreground(theme);
638638

639639
match token.style {
640640
LineStyle::Solid => draw_quad(quad, col),

crates/kas-widgets/src/edit/editor.rs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use kas::event::{
1515
use kas::geom::{Rect, Vec2};
1616
use kas::layout::{AlignHints, AxisInfo, SizeRules};
1717
use kas::prelude::*;
18-
use kas::text::format::Color;
1918
use kas::text::{ConfiguredDisplay, CursorRange, NotReady, SelectionHelper, Status, format};
2019
use kas::theme::{Background, DrawCx, SizeCx, TextClass};
2120
use kas::util::UndoStack;
@@ -38,6 +37,7 @@ pub struct Editor {
3837
id: Id,
3938
read_only: bool,
4039
display: ConfiguredDisplay,
40+
highlight: highlight::Cache,
4141
text: String,
4242
colors: SchemeColors,
4343
selection: SelectionHelper,
@@ -57,6 +57,7 @@ impl Default for Editor {
5757
id: Id::default(),
5858
read_only: false,
5959
display: ConfiguredDisplay::new(TextClass::Editor, false),
60+
highlight: Default::default(),
6061
text: Default::default(),
6162
colors: SchemeColors::default(),
6263
selection: Default::default(),
@@ -100,8 +101,8 @@ impl<S: ToString> From<S> for Editor {
100101
/// support scrolling of text content. Since this component is not a widget it
101102
/// cannot implement [`Viewport`] directly, but it does provide the following
102103
/// methods: [`Self::content_size`], [`Self::draw_with_offset`].
103-
#[autoimpl(Debug where H: trait)]
104-
pub struct Component<H: Highlighter>(pub Editor, highlight::Text<H>);
104+
#[derive(Debug, Default)]
105+
pub struct Component<H: Highlighter>(pub Editor, H);
105106

106107
impl<H: Highlighter> Deref for Component<H> {
107108
type Target = ConfiguredDisplay;
@@ -142,30 +143,23 @@ impl<H: Highlighter> Layout for Component<H> {
142143
}
143144
}
144145

145-
impl<H: Default + Highlighter> Default for Component<H> {
146-
#[inline]
147-
fn default() -> Self {
148-
Component(Editor::default(), Default::default())
149-
}
150-
}
151-
152-
impl<H: Default + Highlighter, S: ToString> From<S> for Component<H> {
146+
impl<H: Highlighter + Default, S: ToString> From<S> for Component<H> {
153147
#[inline]
154148
fn from(text: S) -> Self {
155-
Component(Editor::from(text), Default::default())
149+
Component(Editor::from(text), H::default())
156150
}
157151
}
158152

159153
impl<H: Highlighter> Component<H> {
160154
/// Replace the highlighter
161155
#[inline]
162156
pub fn with_highlighter<H2: Highlighter>(self, highlighter: H2) -> Component<H2> {
163-
Component(self.0, highlight::Text::new(highlighter))
157+
Component(self.0, highlighter)
164158
}
165159

166160
/// Set a new highlighter of the same type
167161
pub fn set_highlighter(&mut self, highlighter: H) {
168-
self.1 = highlight::Text::new(highlighter);
162+
self.1 = highlighter;
169163
}
170164

171165
/// Get the background color
@@ -203,12 +197,6 @@ impl<H: Highlighter> Component<H> {
203197
self.0.display.set_max_status(Status::New);
204198
}
205199
self.0.colors = self.1.scheme_colors();
206-
if self.0.colors.selection_foreground == Color::default() {
207-
self.0.colors.selection_foreground = Color::SELECTION;
208-
}
209-
if self.0.colors.selection_background == Color::default() {
210-
self.0.colors.selection_background = Color::SELECTION;
211-
}
212200
self.0.display.configure(&mut cx.size_cx());
213201

214202
self.prepare(cx);
@@ -217,11 +205,12 @@ impl<H: Highlighter> Component<H> {
217205
#[inline]
218206
fn prepare_runs(&mut self) {
219207
fn inner<H: Highlighter>(this: &mut Component<H>) {
220-
this.1.highlight(&this.0.text);
208+
this.0.highlight.highlight(&this.0.text, &mut this.1);
221209
let (dpem, font) = (this.0.display.font_size(), this.0.display.font());
222-
this.0
223-
.display
224-
.prepare_runs(this.0.text.as_str(), this.1.font_tokens(dpem, font));
210+
this.0.display.prepare_runs(
211+
this.0.text.as_str(),
212+
this.0.highlight.font_tokens(dpem, font),
213+
);
225214
}
226215

227216
if self.0.display.status() < Status::LevelRuns {
@@ -314,7 +303,7 @@ impl<H: Highlighter> Component<H> {
314303
let pos = self.rect().pos - offset;
315304
let range: Range<u32> = self.0.selection.range().cast();
316305

317-
let color_tokens = self.1.color_tokens();
306+
let color_tokens = self.0.highlight.color_tokens();
318307
let default_colors = format::Colors {
319308
foreground: self.0.colors.foreground,
320309
background: None,
@@ -398,7 +387,7 @@ impl<H: Highlighter> Component<H> {
398387
};
399388
draw.text(pos, rect, display, tokens);
400389

401-
let decorations = self.1.decorations();
390+
let decorations = self.0.highlight.decorations();
402391
if !decorations.is_empty() {
403392
draw.decorate_text(pos, rect, display, decorations);
404393
}

crates/kas-widgets/src/edit/highlight.rs

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,40 @@
55

66
//! Supporting elements for syntax highlighting
77
8+
mod cache;
89
#[cfg(feature = "syntect")] mod syntect;
9-
mod text;
1010

11+
pub(crate) use cache::Cache;
12+
use kas::impl_scope;
1113
#[cfg(feature = "syntect")]
1214
pub use syntect::{
1315
SyntaxReference as SyntectSyntax, SyntaxSet as SyntectSyntaxSet, SyntectHighlighter,
1416
};
15-
pub(crate) use text::Text;
1617

1718
use kas::event::ConfigCx;
1819
use kas::text::fonts::{FontStyle, FontWeight};
1920
use kas::text::format::{Color, Colors, Decoration};
2021

21-
/// Colors provided by the highlighter's color scheme
22-
///
23-
/// Note that in each case [`Color::default()`] will resolve to the UI color
24-
/// scheme's color for this property.
25-
#[derive(Debug, Default)]
26-
pub struct SchemeColors {
27-
/// The default text color
28-
pub foreground: Color,
29-
/// The default background color
30-
pub background: Color,
31-
/// The color of the text cursor (sometimes called caret)
32-
pub cursor: Color,
33-
/// The color of selected text
34-
pub selection_foreground: Color,
35-
/// The background color of selected text
36-
pub selection_background: Color,
22+
impl_scope! {
23+
/// Colors provided by the highlighter's color scheme
24+
#[impl_default]
25+
#[derive(Debug)]
26+
pub struct SchemeColors {
27+
/// The default text color
28+
pub foreground: Color,
29+
/// The default background color
30+
pub background: Color,
31+
/// The color of the text cursor (sometimes called caret)
32+
pub cursor: Color,
33+
/// The color of selected text
34+
///
35+
/// Note that the default value is [`Color::SELECTION`].
36+
pub selection_foreground: Color = Color::SELECTION,
37+
/// The background color of selected text
38+
///
39+
/// Note that the default value is [`Color::SELECTION`].
40+
pub selection_background: Color = Color::SELECTION,
41+
}
3742
}
3843

3944
/// A highlighting token
@@ -47,6 +52,9 @@ pub struct SchemeColors {
4752
#[non_exhaustive]
4853
pub struct Token {
4954
/// Text (foreground) and background color
55+
///
56+
/// The background color should be `None` unless highlighting is desired.
57+
/// Specify the default background color using [`SchemeColors::background`].
5058
pub colors: Colors,
5159
/// Text weight (bold/medium/light)
5260
pub weight: FontWeight,

crates/kas-widgets/src/edit/highlight/text.rs renamed to crates/kas-widgets/src/edit/highlight/cache.rs

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,58 +18,27 @@ struct Fmt {
1818
}
1919

2020
/// A highlighted text
21-
///
22-
/// Two `Text` objects compare equal if their formatted text is equal regardless
23-
/// of the embedded highlighter.
24-
#[derive(Clone, Debug)]
25-
#[kas::autoimpl(PartialEq ignore self.highlighter)]
26-
pub(crate) struct Text<H: Highlighter> {
27-
highlighter: H,
21+
#[derive(Clone, Debug, PartialEq)]
22+
pub(crate) struct Cache {
2823
fonts: Vec<Fmt>,
2924
colors: Vec<(u32, Colors)>,
3025
decorations: Vec<(u32, Decoration)>,
3126
}
3227

33-
impl<H: Highlighter + Default> Default for Text<H> {
34-
fn default() -> Self {
35-
Self::new(H::default())
36-
}
37-
}
38-
39-
impl<H: Highlighter> Text<H> {
40-
/// Construct a new instance
28+
impl Default for Cache {
4129
#[inline]
42-
pub fn new(highlighter: H) -> Self {
43-
Text {
44-
highlighter,
30+
fn default() -> Self {
31+
Cache {
4532
fonts: vec![Fmt::default()],
4633
colors: vec![],
4734
decorations: vec![],
4835
}
4936
}
37+
}
5038

51-
/// Configure the highlighter
52-
///
53-
/// This is called when the widget is configured. It may be used to set the
54-
/// theme / color scheme.
55-
///
56-
/// Returns `true` when the highlighter must be re-run.
57-
#[inline]
58-
#[must_use]
59-
pub fn configure(&mut self, cx: &mut ConfigCx) -> bool {
60-
self.highlighter.configure(cx)
61-
}
62-
63-
/// Get scheme colors
64-
///
65-
/// This method allows usage of the highlighter's colors by the editor.
66-
#[inline]
67-
pub fn scheme_colors(&self) -> SchemeColors {
68-
self.highlighter.scheme_colors()
69-
}
70-
39+
impl Cache {
7140
/// Highlight the text (from scratch)
72-
pub fn highlight(&mut self, text: &str) {
41+
pub fn highlight<H: Highlighter>(&mut self, text: &str, highlighter: &mut H) {
7342
self.fonts.clear();
7443
self.fonts.push(Fmt::default());
7544
self.colors.clear();
@@ -110,7 +79,7 @@ impl<H: Highlighter> Text<H> {
11079
state = token;
11180
};
11281

113-
if let Err(err) = self.highlighter.highlight_text(text, &mut push_token) {
82+
if let Err(err) = highlighter.highlight_text(text, &mut push_token) {
11483
log::error!("Highlighting failed: {err}");
11584
debug_assert!(false, "Highlighter: {err}");
11685
}

0 commit comments

Comments
 (0)