summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2024-08-02 20:16:54 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2024-08-02 20:16:54 +0200
commit595bcac243cb9cdd87e7484ab102c86f3235db8a (patch)
treec89c275b175933efc59e9cba68aff607d489a8e2
parentde9ad07b2a4737713f1473641fe195d7e3023928 (diff)
add editor theme
-rw-r--r--src/config/theme/editor/mod.rs74
-rw-r--r--src/config/theme/mod.rs9
-rw-r--r--src/widgets/luaeditor/mod.rs57
-rw-r--r--src/widgets/luaeditor/theme.rs160
-rw-r--r--src/widgets/luaeditor/treesitter.rs36
5 files changed, 257 insertions, 79 deletions
diff --git a/src/config/theme/editor/mod.rs b/src/config/theme/editor/mod.rs
new file mode 100644
index 0000000..d9e2b16
--- /dev/null
+++ b/src/config/theme/editor/mod.rs
@@ -0,0 +1,74 @@
+use mlua::UserData;
+
+use crate::lua::evalsto::EvalTo;
+use crate::widgets::luaeditor::theme::HighlightTheme;
+
+use super::super::GlobalConfig;
+use super::style::Style;
+
+#[derive(Clone, Debug, Default)]
+pub struct EditorTheme {
+ pub background: EvalTo<Style, ()>,
+ pub highlight: HighlightTheme,
+ pub cursor_line: EvalTo<Style, ()>,
+ pub line_number: EvalTo<Style, ()>,
+ pub active_line_number: EvalTo<Style, ()>,
+}
+
+impl EditorTheme {
+ pub const fn new() -> Self {
+ Self {
+ background: EvalTo::Value(Style::new()),
+ highlight: HighlightTheme::new(),
+ cursor_line: EvalTo::Value(Style::new()),
+ line_number: EvalTo::Value(Style::new()),
+ active_line_number: EvalTo::Value(Style::new()),
+ }
+ }
+}
+
+macro_rules! cfg {
+ () => {
+ GlobalConfig::instance().theme.editor
+ };
+}
+
+macro_rules! cfg_mut {
+ () => {
+ GlobalConfig::instance_mut().theme.editor
+ };
+}
+
+impl UserData for EditorTheme {
+ fn add_fields<'lua, F: mlua::prelude::LuaUserDataFields<'lua, Self>>(fields: &mut F) {
+ fields.add_field_function_get("background", |_, _| Ok(cfg!().background.clone()));
+ fields.add_field_function_set("background", |_, _, background: EvalTo<Style, ()>| {
+ cfg_mut!().background = background;
+ Ok(())
+ });
+
+ fields.add_field_function_get("highlight", |_, _| Ok(cfg!().highlight.clone()));
+ fields.add_field_function_set("highlight", |_, _, highlight: HighlightTheme| {
+ cfg_mut!().highlight = highlight;
+ Ok(())
+ });
+
+ fields.add_field_function_get("cursor_line", |_, _| Ok(cfg!().cursor_line.clone()));
+ fields.add_field_function_set("cursor_line", |_, _, cursor_line: EvalTo<Style, ()>| {
+ cfg_mut!().cursor_line = cursor_line;
+ Ok(())
+ });
+
+ fields.add_field_function_get("line_number", |_, _| Ok(cfg!().line_number.clone()));
+ fields.add_field_function_set("line_number", |_, _, line_number: EvalTo<Style, ()>| {
+ cfg_mut!().line_number = line_number;
+ Ok(())
+ });
+
+ fields.add_field_function_get("active_line_number", |_, _| Ok(cfg!().active_line_number.clone()));
+ fields.add_field_function_set("active_line_number", |_, _, active_line_number: EvalTo<Style, ()>| {
+ cfg_mut!().active_line_number = active_line_number;
+ Ok(())
+ });
+ }
+}
diff --git a/src/config/theme/mod.rs b/src/config/theme/mod.rs
index 074a063..ca9723b 100644
--- a/src/config/theme/mod.rs
+++ b/src/config/theme/mod.rs
@@ -1,23 +1,26 @@
use mlua::UserData;
-use self::sheetview::SheetViewTheme;
+use self::{editor::EditorTheme, sheetview::SheetViewTheme};
use super::DUMMY_CONFIG;
pub mod style;
pub mod sheetview;
+pub mod editor;
mod bar;
#[derive(Clone, Debug, Default)]
pub struct Theme {
pub sheetview: SheetViewTheme,
+ pub editor: EditorTheme,
}
impl Theme {
pub const fn new() -> Self {
Self {
sheetview: SheetViewTheme::new(),
+ editor: EditorTheme::new(),
}
}
}
@@ -26,6 +29,10 @@ impl UserData for Theme {
fn add_fields<'lua, F: mlua::prelude::LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_function_get("sheetview", |_, _| {
Ok(DUMMY_CONFIG.theme.sheetview)
+ });
+
+ fields.add_field_function_get("editor", |_, _| {
+ Ok(DUMMY_CONFIG.theme.editor)
})
}
}
diff --git a/src/widgets/luaeditor/mod.rs b/src/widgets/luaeditor/mod.rs
index 0bcffc8..c777190 100644
--- a/src/widgets/luaeditor/mod.rs
+++ b/src/widgets/luaeditor/mod.rs
@@ -1,9 +1,16 @@
use ratatui::{
- crossterm::event::{KeyCode, KeyEvent, KeyModifiers}, text::{ToLine, ToSpan}, widgets::Widget
+ crossterm::event::{KeyCode, KeyEvent, KeyModifiers},
+ layout::Rect,
+ text::{ToLine, ToSpan},
+ widgets::{Paragraph, Widget},
};
use tree_sitter_highlight::HighlightConfiguration;
-use crate::{state::{editor::EditorState, window::Window, GlobalState}, tuicursor::TuiCursor};
+use crate::{
+ config::GlobalConfig,
+ state::{editor::EditorState, window::Window, GlobalState},
+ tuicursor::TuiCursor,
+};
use crate::{cursor::CursorMove, lua};
use super::statusbar::StatusBar;
@@ -87,7 +94,10 @@ impl LuaEditor {
let nr_width = (buffer.lines().len().to_string().len() + 1).max(4) as u16;
Some(TuiCursor {
- position: (buffer.cursor().y() as u16, buffer.cursor().x() as u16 + nr_width),
+ position: (
+ buffer.cursor().y() as u16,
+ buffer.cursor().x() as u16 + nr_width,
+ ),
style: ratatui::crossterm::cursor::SetCursorStyle::SteadyBar,
})
}
@@ -101,6 +111,9 @@ impl Widget for &mut LuaEditor {
let state = GlobalState::instance();
let buffer = &state.editor.buffer;
+ let config = GlobalConfig::instance();
+ let theme = &config.theme.editor;
+
self.bar.render(area, buf);
let inner_area = self.bar.area(area);
@@ -114,6 +127,28 @@ impl Widget for &mut LuaEditor {
let mut span_area = text_area;
let mut current_line = 0;
+ theme
+ .background
+ .get((), &lua::get())
+ .unwrap_or_default()
+ .apply(Paragraph::default())
+ .render(area, buf);
+
+ theme
+ .cursor_line
+ .get((), &lua::get())
+ .unwrap_or_default()
+ .apply(Paragraph::default())
+ .render(
+ Rect::new(
+ text_area.x,
+ text_area.y + buffer.cursor().y() as u16,
+ text_area.width,
+ 1,
+ ),
+ buf,
+ );
+
for (hl, group) in highlights.iter() {
if *group == "\n" {
if current_line >= self.scroll {
@@ -127,7 +162,7 @@ impl Widget for &mut LuaEditor {
let span = group.to_span();
if inner_area.contains(span_area.into()) {
- theme::theme_highlight_group(*hl, span).render(span_area, buf);
+ theme.highlight.highlight(*hl, span).render(span_area, buf);
}
span_area.x += group.len() as u16;
@@ -137,7 +172,7 @@ impl Widget for &mut LuaEditor {
for i in self.scroll..buffer.lines().len() {
let mut nr_area = span_area;
nr_area.x = inner_area.x;
- nr_area.width = nr_width - 1;
+ nr_area.width = nr_width;
nr_area.y = inner_area.y + (i - self.scroll) as u16;
nr_area.height = 1;
@@ -145,7 +180,17 @@ impl Widget for &mut LuaEditor {
break;
}
- (i + 1).to_line().right_aligned().render(nr_area, buf);
+ if buffer.cursor().y() == i {
+ theme
+ .active_line_number
+ .get((), &lua::get())
+ .unwrap_or_default()
+ } else {
+ theme.line_number.get((), &lua::get()).unwrap_or_default()
+ }
+ .apply(((i + 1).to_string() + " ").to_line())
+ .right_aligned()
+ .render(nr_area, buf);
}
}
}
diff --git a/src/widgets/luaeditor/theme.rs b/src/widgets/luaeditor/theme.rs
index 38e4498..f0520f4 100644
--- a/src/widgets/luaeditor/theme.rs
+++ b/src/widgets/luaeditor/theme.rs
@@ -1,45 +1,127 @@
-use ratatui::{
- style::{Color, Stylize},
- text::Span,
-};
+use mlua::{FromLua, IntoLua};
+use ratatui::{style::Color, text::Span};
use tree_sitter_highlight::Highlight;
-static HIGHLIGHT_THEME: [Color; 29] = [
- Color::White, // attribute
- Color::White, // boolean
- Color::DarkGray, // comment
- Color::LightYellow, // conditional
- Color::White, // constant
- Color::White, // constant.builtin
- Color::White, // constructor
- Color::White, // field
- Color::White, // function
- Color::White, // function.builtin
- Color::White, // function.call
- Color::Yellow, // keyword
- Color::LightYellow, // keyword.function
- Color::White, // keyword.operator
- Color::LightYellow, // keyword.return
- Color::White, // label
- Color::White, // method
- Color::White, // method.call
- Color::Blue, // number
- Color::Gray, // operator
- Color::White, // parameter
- Color::White, // preproc
- Color::Gray, // punctuation.bracket
- Color::Gray, // punctuation.delimiter
- Color::LightYellow, // repeat
- Color::LightGreen, // string
- Color::Yellow, // string.escape
- Color::Gray, // variable
- Color::White, // variable.builtin
+use crate::config::theme::style::Style;
+
+pub(super) static HIGHLIGHT_NAMES: [&str; 29] = [
+ "attribute",
+ "boolean",
+ "comment",
+ "conditional",
+ "constant",
+ "constant.builtin",
+ "constructor",
+ "field",
+ "function",
+ "function.builtin",
+ "function.call",
+ "keyword",
+ "keyword.function",
+ "keyword.operator",
+ "keyword.return",
+ "label",
+ "method",
+ "method.call",
+ "number",
+ "operator",
+ "parameter",
+ "preproc",
+ "punctuation.bracket",
+ "punctuation.delimiter",
+ "repeat",
+ "string",
+ "string.escape",
+ "variable",
+ "variable.builtin",
];
-pub fn theme_highlight_group(hl: Option<Highlight>, span: Span) -> Span {
- if let Some(hl) = hl {
- span.fg(HIGHLIGHT_THEME[hl.0])
- } else {
- span
+#[derive(Default, Debug, Clone)]
+pub struct HighlightTheme {
+ theme: [Style; 29],
+}
+
+impl HighlightTheme {
+ pub const fn new() -> Self {
+ Self {
+ theme: [
+ Style::new().fg(Color::White), // attribute
+ Style::new().fg(Color::White), // boolean
+ Style::new().fg(Color::White), // comment
+ Style::new().fg(Color::White), // conditional
+ Style::new().fg(Color::White), // constant
+ Style::new().fg(Color::White), // constant.builtin
+ Style::new().fg(Color::White), // constructor
+ Style::new().fg(Color::White), // field
+ Style::new().fg(Color::White), // function
+ Style::new().fg(Color::White), // function.builtin
+ Style::new().fg(Color::White), // function.call
+ Style::new().fg(Color::White), // keyword
+ Style::new().fg(Color::White), // keyword.function
+ Style::new().fg(Color::White), // keyword.operator
+ Style::new().fg(Color::White), // keyword.return
+ Style::new().fg(Color::White), // label
+ Style::new().fg(Color::White), // method
+ Style::new().fg(Color::White), // method.call
+ Style::new().fg(Color::White), // number
+ Style::new().fg(Color::White), // operator
+ Style::new().fg(Color::White), // parameter
+ Style::new().fg(Color::White), // preproc
+ Style::new().fg(Color::White), // punctuation.bracket
+ Style::new().fg(Color::White), // punctuation.delimiter
+ Style::new().fg(Color::White), // repeat
+ Style::new().fg(Color::White), // string
+ Style::new().fg(Color::White), // string.escape
+ Style::new().fg(Color::White), // variable
+ Style::new().fg(Color::White), // variable.builtin
+ ],
+ }
+ }
+
+ pub fn highlight<'a>(&'a self, hl: Option<Highlight>, span: Span<'a>) -> Span<'a> {
+ if let Some(hl) = hl {
+ self.theme[hl.0].apply(span)
+ } else {
+ span
+ }
+ }
+}
+
+impl<'lua> IntoLua<'lua> for HighlightTheme {
+ fn into_lua(
+ self,
+ lua: &'lua mlua::prelude::Lua,
+ ) -> mlua::prelude::LuaResult<mlua::prelude::LuaValue<'lua>> {
+ let table = lua.create_table()?;
+
+ for (i, names) in HIGHLIGHT_NAMES.iter().enumerate() {
+ table.set(names.replace('.', "_"), self.theme[i])?
+ }
+
+ table.into_lua(lua)
+ }
+}
+
+impl<'lua> FromLua<'lua> for HighlightTheme {
+ fn from_lua(
+ value: mlua::prelude::LuaValue<'lua>,
+ _lua: &'lua mlua::prelude::Lua,
+ ) -> mlua::prelude::LuaResult<Self> {
+ let mut theme = HighlightTheme::default();
+
+ if value.is_table() {
+ let table = value.as_table().unwrap();
+ for (i, names) in HIGHLIGHT_NAMES.iter().enumerate() {
+ if let Ok(style) = table.get(names.replace('.', "_")) {
+ theme.theme[i] = style;
+ }
+ }
+
+ Ok(theme)
+ } else {
+ Err(mlua::prelude::LuaError::runtime(
+ "failed to parse HighlightTheme",
+ ))
+ }
}
}
diff --git a/src/widgets/luaeditor/treesitter.rs b/src/widgets/luaeditor/treesitter.rs
index 1474434..ecd782d 100644
--- a/src/widgets/luaeditor/treesitter.rs
+++ b/src/widgets/luaeditor/treesitter.rs
@@ -1,36 +1,6 @@
use tree_sitter_highlight::{Highlight, HighlightConfiguration, HighlightEvent, Highlighter};
-static HIGHLIGHT_NAMES: [&str; 29] = [
- "attribute",
- "boolean",
- "comment",
- "conditional",
- "constant",
- "constant.builtin",
- "constructor",
- "field",
- "function",
- "function.builtin",
- "function.call",
- "keyword",
- "keyword.function",
- "keyword.operator",
- "keyword.return",
- "label",
- "method",
- "method.call",
- "number",
- "operator",
- "parameter",
- "preproc",
- "punctuation.bracket",
- "punctuation.delimiter",
- "repeat",
- "string",
- "string.escape",
- "variable",
- "variable.builtin",
-];
+use super::theme;
pub fn new_highlight_configuration() -> HighlightConfiguration {
let mut highlight_config = HighlightConfiguration::new(
@@ -42,13 +12,13 @@ pub fn new_highlight_configuration() -> HighlightConfiguration {
)
.unwrap();
- highlight_config.configure(&HIGHLIGHT_NAMES);
+ highlight_config.configure(&theme::HIGHLIGHT_NAMES);
highlight_config
}
pub fn highlight_name(h: Highlight) -> &'static str {
- HIGHLIGHT_NAMES[h.0]
+ theme::HIGHLIGHT_NAMES[h.0]
}
pub fn highlighter_split<'a>(