use crate::{
core::{
crossterm::{
self,
event::Event,
style::{Attribute, Attributes, Color, ContentStyle},
},
render::{Renderer, SharedRenderer},
Widget,
},
preset::Evaluator,
widgets::{
jsonstream::{
self,
config::{Config, OverflowMode},
JsonStream,
},
text::{self, Text},
},
Signal,
};
pub mod evaluate;
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Index {
Title = 0,
Json = 1,
}
pub struct Json {
pub renderer: Option<SharedRenderer<Index>>,
pub evaluator: Evaluator<Self>,
pub title: text::State,
pub json: jsonstream::State,
}
#[async_trait::async_trait]
impl crate::Prompt for Json {
async fn initialize(&mut self) -> anyhow::Result<()> {
let size = crossterm::terminal::size()?;
self.renderer = Some(SharedRenderer::new(
Renderer::try_new_with_graphemes(
[
(Index::Title, self.title.create_graphemes(size.0, size.1)),
(Index::Json, self.json.create_graphemes(size.0, size.1)),
],
true,
)
.await?,
));
Ok(())
}
async fn evaluate(&mut self, event: &Event) -> anyhow::Result<Signal> {
let ret = (self.evaluator)(event, self).await;
let size = crossterm::terminal::size()?;
self.render(size.0, size.1).await?;
ret
}
type Return = ();
fn finalize(&mut self) -> anyhow::Result<Self::Return> {
Ok(())
}
}
impl Json {
pub fn new(stream: JsonStream) -> Self {
Self {
renderer: None,
evaluator: |event, ctx| Box::pin(evaluate::default(event, ctx)),
title: text::State {
config: text::config::Config {
style: Some(ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
}),
..Default::default()
},
..Default::default()
},
json: jsonstream::State {
stream,
config: Config {
curly_brackets_style: ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
square_brackets_style: ContentStyle {
attributes: Attributes::from(Attribute::Bold),
..Default::default()
},
key_style: ContentStyle {
foreground_color: Some(Color::DarkBlue),
..Default::default()
},
string_value_style: ContentStyle {
foreground_color: Some(Color::DarkGreen),
..Default::default()
},
number_value_style: ContentStyle::default(),
boolean_value_style: ContentStyle::default(),
null_value_style: ContentStyle {
foreground_color: Some(Color::DarkGrey),
..Default::default()
},
active_item_attribute: Attribute::Undercurled,
inactive_item_attribute: Attribute::Dim,
indent: 2,
overflow_mode: OverflowMode::Truncate,
lines: Default::default(),
},
},
}
}
pub fn title<T: AsRef<str>>(mut self, text: T) -> Self {
self.title.text = Text::from(text);
self
}
pub fn title_style(mut self, style: ContentStyle) -> Self {
self.title.config.style = Some(style);
self
}
pub fn json_lines(mut self, lines: usize) -> Self {
self.json.config.lines = Some(lines);
self
}
pub fn indent(mut self, indent: usize) -> Self {
self.json.config.indent = indent;
self
}
pub fn overflow_mode(mut self, mode: OverflowMode) -> Self {
self.json.config.overflow_mode = mode;
self
}
pub fn active_item_attribute(mut self, attr: Attribute) -> Self {
self.json.config.active_item_attribute = attr;
self
}
pub fn inactive_item_attribute(mut self, attr: Attribute) -> Self {
self.json.config.inactive_item_attribute = attr;
self
}
pub fn evaluator(mut self, evaluator: Evaluator<Self>) -> Self {
self.evaluator = evaluator;
self
}
async fn render(&mut self, width: u16, height: u16) -> anyhow::Result<()> {
match self.renderer.as_ref() {
Some(renderer) => {
renderer
.update([
(Index::Title, self.title.create_graphemes(width, height)),
(Index::Json, self.json.create_graphemes(width, height)),
])
.render()
.await
}
None => Err(anyhow::anyhow!("Renderer not initialized")),
}
}
}