mirror of https://github.com/sayanarijit/xplr
Allow custom title and ui config in custom layout. (#589)
* Allow custom title and ui config in custom layout. Adds the following layouts: - Static - Dynamic Deprecates `CustomContent` (but won't be removed to maintain compatibility). Closes: https://github.com/sayanarijit/xplr/issues/563 * Delete init.lua * Update docs/en/src/layout.md * Update docs/en/src/layout.md * Rename - Paragraph => CustomParagraph - List => CustomList - Table => CustomTable Also update init.lua * Fix clippy errs * Fix doc linkspull/591/head
parent
6595e2ee93
commit
08e1f6aa2d
@ -0,0 +1,224 @@
|
|||||||
|
// Things of the past, mostly bad decisions, which cannot erased, stays in this
|
||||||
|
// haunted module.
|
||||||
|
|
||||||
|
use crate::app;
|
||||||
|
use crate::lua;
|
||||||
|
use crate::ui::block;
|
||||||
|
use crate::ui::string_to_text;
|
||||||
|
use crate::ui::Constraint;
|
||||||
|
use crate::ui::ContentRendererArg;
|
||||||
|
use mlua::Lua;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tui::backend::Backend;
|
||||||
|
use tui::layout::Constraint as TuiConstraint;
|
||||||
|
use tui::layout::Rect as TuiRect;
|
||||||
|
use tui::widgets::Cell;
|
||||||
|
use tui::widgets::List;
|
||||||
|
use tui::widgets::ListItem;
|
||||||
|
use tui::widgets::Paragraph;
|
||||||
|
use tui::widgets::Row;
|
||||||
|
use tui::widgets::Table;
|
||||||
|
use tui::Frame;
|
||||||
|
|
||||||
|
/// A cursed enum from crate::ui.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub enum ContentBody {
|
||||||
|
/// A paragraph to render
|
||||||
|
StaticParagraph { render: String },
|
||||||
|
|
||||||
|
/// A Lua function that returns a paragraph to render
|
||||||
|
DynamicParagraph { render: String },
|
||||||
|
|
||||||
|
/// List to render
|
||||||
|
StaticList { render: Vec<String> },
|
||||||
|
|
||||||
|
/// A Lua function that returns lines to render
|
||||||
|
DynamicList { render: String },
|
||||||
|
|
||||||
|
/// A table to render
|
||||||
|
StaticTable {
|
||||||
|
widths: Vec<Constraint>,
|
||||||
|
col_spacing: Option<u16>,
|
||||||
|
render: Vec<Vec<String>>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A Lua function that returns a table to render
|
||||||
|
DynamicTable {
|
||||||
|
widths: Vec<Constraint>,
|
||||||
|
col_spacing: Option<u16>,
|
||||||
|
render: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A cursed struct from crate::ui.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct CustomContent {
|
||||||
|
pub title: Option<String>,
|
||||||
|
pub body: ContentBody,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A cursed function from crate::ui.
|
||||||
|
pub fn draw_custom_content<B: Backend>(
|
||||||
|
f: &mut Frame<B>,
|
||||||
|
screen_size: TuiRect,
|
||||||
|
layout_size: TuiRect,
|
||||||
|
app: &app::App,
|
||||||
|
content: CustomContent,
|
||||||
|
lua: &Lua,
|
||||||
|
) {
|
||||||
|
let config = app.config.general.panel_ui.default.clone();
|
||||||
|
let title = content.title;
|
||||||
|
let body = content.body;
|
||||||
|
|
||||||
|
match body {
|
||||||
|
ContentBody::StaticParagraph { render } => {
|
||||||
|
let render = string_to_text(render);
|
||||||
|
let content = Paragraph::new(render).block(block(
|
||||||
|
config,
|
||||||
|
title.map(|t| format!(" {t} ")).unwrap_or_default(),
|
||||||
|
));
|
||||||
|
f.render_widget(content, layout_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBody::DynamicParagraph { render } => {
|
||||||
|
let ctx = ContentRendererArg {
|
||||||
|
app: app.to_lua_ctx_light(),
|
||||||
|
layout_size: layout_size.into(),
|
||||||
|
screen_size: screen_size.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let render = lua::serialize(lua, &ctx)
|
||||||
|
.map(|arg| {
|
||||||
|
lua::call(lua, &render, arg).unwrap_or_else(|e| format!("{e:?}"))
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|e| e.to_string());
|
||||||
|
|
||||||
|
let render = string_to_text(render);
|
||||||
|
|
||||||
|
let content = Paragraph::new(render).block(block(
|
||||||
|
config,
|
||||||
|
title.map(|t| format!(" {t} ")).unwrap_or_default(),
|
||||||
|
));
|
||||||
|
f.render_widget(content, layout_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBody::StaticList { render } => {
|
||||||
|
let items = render
|
||||||
|
.into_iter()
|
||||||
|
.map(string_to_text)
|
||||||
|
.map(ListItem::new)
|
||||||
|
.collect::<Vec<ListItem>>();
|
||||||
|
|
||||||
|
let content = List::new(items).block(block(
|
||||||
|
config,
|
||||||
|
title.map(|t| format!(" {t} ")).unwrap_or_default(),
|
||||||
|
));
|
||||||
|
f.render_widget(content, layout_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBody::DynamicList { render } => {
|
||||||
|
let ctx = ContentRendererArg {
|
||||||
|
app: app.to_lua_ctx_light(),
|
||||||
|
layout_size: layout_size.into(),
|
||||||
|
screen_size: screen_size.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let items = lua::serialize(lua, &ctx)
|
||||||
|
.map(|arg| {
|
||||||
|
lua::call(lua, &render, arg)
|
||||||
|
.unwrap_or_else(|e| vec![format!("{e:?}")])
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|e| vec![e.to_string()])
|
||||||
|
.into_iter()
|
||||||
|
.map(string_to_text)
|
||||||
|
.map(ListItem::new)
|
||||||
|
.collect::<Vec<ListItem>>();
|
||||||
|
|
||||||
|
let content = List::new(items).block(block(
|
||||||
|
config,
|
||||||
|
title.map(|t| format!(" {t} ")).unwrap_or_default(),
|
||||||
|
));
|
||||||
|
f.render_widget(content, layout_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBody::StaticTable {
|
||||||
|
widths,
|
||||||
|
col_spacing,
|
||||||
|
render,
|
||||||
|
} => {
|
||||||
|
let rows = render
|
||||||
|
.into_iter()
|
||||||
|
.map(|cols| {
|
||||||
|
Row::new(
|
||||||
|
cols.into_iter()
|
||||||
|
.map(string_to_text)
|
||||||
|
.map(Cell::from)
|
||||||
|
.collect::<Vec<Cell>>(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<Row>>();
|
||||||
|
|
||||||
|
let widths = widths
|
||||||
|
.into_iter()
|
||||||
|
.map(|w| w.to_tui(screen_size, layout_size))
|
||||||
|
.collect::<Vec<TuiConstraint>>();
|
||||||
|
|
||||||
|
let content = Table::new(rows)
|
||||||
|
.widths(&widths)
|
||||||
|
.column_spacing(col_spacing.unwrap_or(1))
|
||||||
|
.block(block(
|
||||||
|
config,
|
||||||
|
title.map(|t| format!(" {t} ")).unwrap_or_default(),
|
||||||
|
));
|
||||||
|
|
||||||
|
f.render_widget(content, layout_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBody::DynamicTable {
|
||||||
|
widths,
|
||||||
|
col_spacing,
|
||||||
|
render,
|
||||||
|
} => {
|
||||||
|
let ctx = ContentRendererArg {
|
||||||
|
app: app.to_lua_ctx_light(),
|
||||||
|
layout_size: layout_size.into(),
|
||||||
|
screen_size: screen_size.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let rows = lua::serialize(lua, &ctx)
|
||||||
|
.map(|arg| {
|
||||||
|
lua::call(lua, &render, arg)
|
||||||
|
.unwrap_or_else(|e| vec![vec![format!("{e:?}")]])
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|e| vec![vec![e.to_string()]])
|
||||||
|
.into_iter()
|
||||||
|
.map(|cols| {
|
||||||
|
Row::new(
|
||||||
|
cols.into_iter()
|
||||||
|
.map(string_to_text)
|
||||||
|
.map(Cell::from)
|
||||||
|
.collect::<Vec<Cell>>(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<Row>>();
|
||||||
|
|
||||||
|
let widths = widths
|
||||||
|
.into_iter()
|
||||||
|
.map(|w| w.to_tui(screen_size, layout_size))
|
||||||
|
.collect::<Vec<TuiConstraint>>();
|
||||||
|
|
||||||
|
let mut content = Table::new(rows).widths(&widths).block(block(
|
||||||
|
config,
|
||||||
|
title.map(|t| format!(" {t} ")).unwrap_or_default(),
|
||||||
|
));
|
||||||
|
|
||||||
|
if let Some(col_spacing) = col_spacing {
|
||||||
|
content = content.column_spacing(col_spacing);
|
||||||
|
};
|
||||||
|
|
||||||
|
f.render_widget(content, layout_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue