use crate::{
ecs::components::{
buffer::{EditorView, FocusedEditorView},
vim::VimModalState,
},
vim::VimConfig,
};
use bevy::prelude::{
BackgroundColor, Color, DetectChanges, Node, PositionType, Query, Ref, Res, ResMut, Resource,
Text, TextColor, TextFont, UiRect, Val, With,
};
use haalka::prelude::*;
use super::{
STATUS_BAR_HEIGHT,
status::{StatusLineKind, render_search_status},
};
const STATUS_FONT_SIZE: f32 = 18.0;
const STATUS_BAR_BACKGROUND: Color = Color::srgb(0.0, 0.12, 0.15);
#[derive(Clone, Debug, Default, Eq, PartialEq, Resource)]
pub struct ChromeStatusLine {
text: String,
is_error: bool,
}
impl ChromeStatusLine {
const fn new(text: String, kind: StatusLineKind) -> Self {
Self {
text,
is_error: matches!(kind, StatusLineKind::Error),
}
}
}
pub fn spawn_chrome(world: &mut bevy::prelude::World) {
let _chrome_entity = chrome_root().spawn(world);
}
pub fn sync_chrome_status_line(
vim_config: Res<VimConfig>,
modal_query: Query<Ref<VimModalState>, (With<EditorView>, With<FocusedEditorView>)>,
mut chrome_status_line: ResMut<ChromeStatusLine>,
) {
let Some(modal_state) = modal_query.iter().next() else {
return;
};
if !modal_state.is_changed() && !vim_config.is_changed() {
return;
}
let vim_config = vim_config.into_inner();
let rendered = render_search_status(
&modal_state.search,
&modal_state.command,
&modal_state.leader,
vim_config,
&modal_state.status,
);
let next = ChromeStatusLine::new(rendered.text, rendered.kind);
if *chrome_status_line != next {
*chrome_status_line = next;
}
}
fn chrome_root() -> impl Element {
El::<Node>::new()
.with_node(|mut node| {
node.position_type = PositionType::Absolute;
node.left = Val::Px(0.0);
node.right = Val::Px(0.0);
node.bottom = Val::Px(0.0);
node.height = Val::Px(STATUS_BAR_HEIGHT);
node.padding = UiRect::horizontal(Val::Px(8.0));
})
.background_color(BackgroundColor(STATUS_BAR_BACKGROUND))
.align_content(Align::new().left().center_y())
.child(status_text())
}
fn status_text() -> impl Element {
El::<Text>::new()
.text_font(TextFont::from_font_size(STATUS_FONT_SIZE))
.text_signal(
signal::from_resource_changed::<ChromeStatusLine>()
.map_in(|status| Some(Text::new(status.text))),
)
.text_color_signal(
signal::from_resource_changed::<ChromeStatusLine>().map_in(|status| {
Some(TextColor(if status.is_error {
Color::srgb_u8(0xff, 0x66, 0x66)
} else {
Color::srgb_u8(0xD8, 0xF3, 0xF8)
}))
}),
)
}