Skip to content

Commit

Permalink
Implement theme selector in editor example
Browse files Browse the repository at this point in the history
  • Loading branch information
hecrj committed Sep 18, 2023
1 parent 61ef8f3 commit 8446fe6
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 22 deletions.
7 changes: 5 additions & 2 deletions core/src/text/highlighter.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::Color;

use std::hash::Hash;
use std::ops::Range;

pub trait Highlighter: 'static {
type Settings: Hash;
type Settings: PartialEq + Clone;
type Highlight;

type Iterator<'a>: Iterator<Item = (Range<usize>, Self::Highlight)>
Expand All @@ -13,6 +12,8 @@ pub trait Highlighter: 'static {

fn new(settings: &Self::Settings) -> Self;

fn update(&mut self, new_settings: &Self::Settings);

fn change_line(&mut self, line: usize);

fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_>;
Expand All @@ -38,6 +39,8 @@ impl Highlighter for PlainText {
Self
}

fn update(&mut self, _new_settings: &Self::Settings) {}

fn change_line(&mut self, _line: usize) {}

fn highlight_line(&mut self, _line: &str) -> Self::Iterator<'_> {
Expand Down
101 changes: 82 additions & 19 deletions examples/editor/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use iced::widget::{container, text_editor};
use iced::{Element, Font, Sandbox, Settings, Theme};
use iced::widget::{column, horizontal_space, pick_list, row, text_editor};
use iced::{Element, Font, Length, Sandbox, Settings, Theme};

use highlighter::Highlighter;

Expand All @@ -9,21 +9,22 @@ pub fn main() -> iced::Result {

struct Editor {
content: text_editor::Content,
theme: highlighter::Theme,
}

#[derive(Debug, Clone)]
enum Message {
Edit(text_editor::Action),
ThemeSelected(highlighter::Theme),
}

impl Sandbox for Editor {
type Message = Message;

fn new() -> Self {
Self {
content: text_editor::Content::with(include_str!(
"../../../README.md"
)),
content: text_editor::Content::with(include_str!("main.rs")),
theme: highlighter::Theme::SolarizedDark,
}
}

Expand All @@ -36,18 +37,33 @@ impl Sandbox for Editor {
Message::Edit(action) => {
self.content.edit(action);
}
Message::ThemeSelected(theme) => {
self.theme = theme;
}
}
}

fn view(&self) -> Element<Message> {
container(
column![
row![
horizontal_space(Length::Fill),
pick_list(
highlighter::Theme::ALL,
Some(self.theme),
Message::ThemeSelected
)
.padding([5, 10])
]
.spacing(10),
text_editor(&self.content)
.on_edit(Message::Edit)
.font(Font::with_name("Hasklug Nerd Font Mono"))
.highlight::<Highlighter>(highlighter::Settings {
token: String::from("md"),
theme: self.theme,
extension: String::from("rs"),
}),
)
]
.spacing(10)
.padding(20)
.into()
}
Expand All @@ -60,21 +76,52 @@ impl Sandbox for Editor {
mod highlighter {
use iced::advanced::text::highlighter;
use iced::widget::text_editor;
use iced::{Color, Font, Theme};
use iced::{Color, Font};

use std::ops::Range;
use syntect::highlighting;
use syntect::parsing::{self, SyntaxReference};

#[derive(Debug, Clone, Hash)]
#[derive(Debug, Clone, PartialEq)]
pub struct Settings {
pub token: String,
pub theme: Theme,
pub extension: String,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Theme {
SolarizedDark,
InspiredGitHub,
Base16Mocha,
}

impl Theme {
pub const ALL: &[Self] =
&[Self::SolarizedDark, Self::InspiredGitHub, Self::Base16Mocha];

fn key(&self) -> &'static str {
match self {
Theme::InspiredGitHub => "InspiredGitHub",
Theme::Base16Mocha => "base16-mocha.dark",
Theme::SolarizedDark => "Solarized (dark)",
}
}
}

impl std::fmt::Display for Theme {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Theme::InspiredGitHub => write!(f, "Inspired GitHub"),
Theme::Base16Mocha => write!(f, "Mocha"),
Theme::SolarizedDark => write!(f, "Solarized Dark"),
}
}
}

pub struct Highlight(highlighting::StyleModifier);

impl text_editor::Highlight for Highlight {
fn format(&self, _theme: &Theme) -> highlighter::Format<Font> {
fn format(&self, _theme: &iced::Theme) -> highlighter::Format<Font> {
highlighter::Format {
color: self.0.foreground.map(|color| {
Color::from_rgba8(
Expand All @@ -92,8 +139,8 @@ mod highlighter {
pub struct Highlighter {
syntaxes: parsing::SyntaxSet,
syntax: SyntaxReference,
caches: Vec<(parsing::ParseState, parsing::ScopeStack)>,
theme: highlighting::Theme,
caches: Vec<(parsing::ParseState, parsing::ScopeStack)>,
current_line: usize,
}

Expand All @@ -110,26 +157,42 @@ mod highlighter {
let syntaxes = parsing::SyntaxSet::load_defaults_nonewlines();

let syntax = syntaxes
.find_syntax_by_token(&settings.token)
.find_syntax_by_token(&settings.extension)
.unwrap_or_else(|| syntaxes.find_syntax_plain_text());

let parser = parsing::ParseState::new(syntax);
let stack = parsing::ScopeStack::new();

let theme = highlighting::ThemeSet::load_defaults()
.themes
.remove("base16-mocha.dark")
.remove(settings.theme.key())
.unwrap();

let parser = parsing::ParseState::new(syntax);
let stack = parsing::ScopeStack::new();

Highlighter {
syntax: syntax.clone(),
syntaxes,
caches: vec![(parser, stack)],
theme,
caches: vec![(parser, stack)],
current_line: 0,
}
}

fn update(&mut self, new_settings: &Self::Settings) {
self.syntax = self
.syntaxes
.find_syntax_by_token(&new_settings.extension)
.unwrap_or_else(|| self.syntaxes.find_syntax_plain_text())
.clone();

self.theme = highlighting::ThemeSet::load_defaults()
.themes
.remove(new_settings.theme.key())
.unwrap();

// Restart the highlighter
self.change_line(0);
}

fn change_line(&mut self, line: usize) {
let snapshot = line / LINES_PER_SNAPSHOT;

Expand Down
13 changes: 12 additions & 1 deletion widget/src/text_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,12 @@ where
}
}

struct State<Highlighter> {
struct State<Highlighter: text::Highlighter> {
is_focused: bool,
last_click: Option<mouse::Click>,
drag_click: Option<mouse::click::Kind>,
highlighter: RefCell<Highlighter>,
highlighter_settings: Highlighter::Settings,
}

impl<'a, Highlighter, Message, Renderer> Widget<Message, Renderer>
Expand All @@ -220,6 +221,7 @@ where
highlighter: RefCell::new(Highlighter::new(
&self.highlighter_settings,
)),
highlighter_settings: self.highlighter_settings.clone(),
})
}

Expand All @@ -240,6 +242,15 @@ where
let mut internal = self.content.0.borrow_mut();
let state = tree.state.downcast_mut::<State<Highlighter>>();

if state.highlighter_settings != self.highlighter_settings {
state
.highlighter
.borrow_mut()
.update(&self.highlighter_settings);

state.highlighter_settings = self.highlighter_settings.clone();
}

internal.editor.update(
limits.pad(self.padding).max(),
self.font.unwrap_or_else(|| renderer.default_font()),
Expand Down

0 comments on commit 8446fe6

Please sign in to comment.