chore: refactor into classic
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
parent
46cf74da3a
commit
b3d6b77752
@ -1,249 +1,3 @@
|
|||||||
|
pub(crate) mod graph_explorer;
|
||||||
pub(crate) mod movement_graph;
|
pub(crate) mod movement_graph;
|
||||||
pub(crate) mod render_graph;
|
pub(crate) mod render_graph;
|
||||||
|
|
||||||
pub(crate) mod graph_explorer {
|
|
||||||
use anyhow::Result;
|
|
||||||
use hyperlog_core::log::GraphItem;
|
|
||||||
use ratatui::{prelude::*, widgets::*};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
command_parser::Commands, components::movement_graph::GraphItemType, models::Msg,
|
|
||||||
state::SharedState,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::movement_graph::{MovementGraph, MovementGraphItem};
|
|
||||||
use super::render_graph::RenderGraph;
|
|
||||||
|
|
||||||
pub struct GraphExplorer<'a> {
|
|
||||||
state: SharedState,
|
|
||||||
|
|
||||||
pub inner: GraphExplorerState<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GraphExplorerState<'a> {
|
|
||||||
root: String,
|
|
||||||
|
|
||||||
current_path: Option<&'a str>,
|
|
||||||
current_position: Vec<usize>,
|
|
||||||
|
|
||||||
graph: Option<GraphItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> GraphExplorer<'a> {
|
|
||||||
pub fn new(root: String, state: SharedState) -> Self {
|
|
||||||
Self {
|
|
||||||
state,
|
|
||||||
inner: GraphExplorerState::<'a> {
|
|
||||||
root,
|
|
||||||
current_path: None,
|
|
||||||
current_position: Vec::new(),
|
|
||||||
graph: None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_graph(&mut self) -> Result<&mut Self> {
|
|
||||||
let now = std::time::SystemTime::now();
|
|
||||||
|
|
||||||
let graph = self
|
|
||||||
.state
|
|
||||||
.querier
|
|
||||||
.get(
|
|
||||||
&self.inner.root,
|
|
||||||
self.inner
|
|
||||||
.current_path
|
|
||||||
.map(|p| p.split('.').collect::<Vec<_>>())
|
|
||||||
.unwrap_or_default(),
|
|
||||||
)
|
|
||||||
.ok_or(anyhow::anyhow!("graph should've had an item"))?;
|
|
||||||
|
|
||||||
self.inner.graph = Some(graph);
|
|
||||||
|
|
||||||
let elapsed = now.elapsed()?;
|
|
||||||
tracing::trace!("Graph.update_graph took: {}nanos", elapsed.as_nanos());
|
|
||||||
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn linearize_graph(&self) -> Option<MovementGraph> {
|
|
||||||
self.inner.graph.clone().map(|g| g.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Will only incrmeent to the next level
|
|
||||||
///
|
|
||||||
/// Current: 0.1.0
|
|
||||||
/// Available: 0.1.0.[0,1,2]
|
|
||||||
/// Choses: 0.1.0.0 else nothing
|
|
||||||
pub(crate) fn move_right(&mut self) -> Result<()> {
|
|
||||||
if let Some(graph) = self.linearize_graph() {
|
|
||||||
tracing::debug!("graph: {:?}", graph);
|
|
||||||
let position_items = &self.inner.current_position;
|
|
||||||
|
|
||||||
if let Some(next_item) = graph.next_right(position_items) {
|
|
||||||
self.inner.current_position.push(next_item.index);
|
|
||||||
tracing::trace!("found next item: {:?}", self.inner.current_position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Will only incrmeent to the next level
|
|
||||||
///
|
|
||||||
/// Current: 0.1.0
|
|
||||||
/// Available: 0.[0,1,2].0
|
|
||||||
/// Choses: 0.1 else nothing
|
|
||||||
pub(crate) fn move_left(&mut self) -> Result<()> {
|
|
||||||
if let Some(last) = self.inner.current_position.pop() {
|
|
||||||
tracing::trace!(
|
|
||||||
"found last item: {:?}, popped: {}",
|
|
||||||
self.inner.current_position,
|
|
||||||
last
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Will move up if a sibling exists, or up to the most common sibling between sections
|
|
||||||
///
|
|
||||||
/// Current: 0.1.1
|
|
||||||
/// Available: 0.[0.[0,1],1.[0,1]]
|
|
||||||
/// Chose: 0.1.0 again 0.0 We don't choose a subitem in the next three instead we just find the most common sibling
|
|
||||||
pub(crate) fn move_up(&mut self) -> Result<()> {
|
|
||||||
if let Some(graph) = self.linearize_graph() {
|
|
||||||
let position_items = &self.inner.current_position;
|
|
||||||
|
|
||||||
if let Some(next_item) = graph.next_up(position_items) {
|
|
||||||
self.inner.current_position = next_item;
|
|
||||||
tracing::trace!("found next up: {:?}", self.inner.current_position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Will move down if a sibling exists, or down to the most common sibling between sections
|
|
||||||
///
|
|
||||||
/// Current: 0.0.0
|
|
||||||
/// Available: 0.[0.[0,1],1.[0,1]]
|
|
||||||
/// Chose: 0.0.1 again 0.1
|
|
||||||
pub(crate) fn move_down(&mut self) -> Result<()> {
|
|
||||||
if let Some(graph) = self.linearize_graph() {
|
|
||||||
let position_items = &self.inner.current_position;
|
|
||||||
|
|
||||||
if let Some(next_item) = graph.next_down(position_items) {
|
|
||||||
self.inner.current_position = next_item;
|
|
||||||
tracing::trace!("found next down: {:?}", self.inner.current_position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_current_path(&self) -> Vec<String> {
|
|
||||||
let graph = self.linearize_graph();
|
|
||||||
let position_items = &self.inner.current_position;
|
|
||||||
|
|
||||||
if let Some(graph) = graph {
|
|
||||||
graph.to_current_path(position_items)
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_current_item(&self) -> Option<MovementGraphItem> {
|
|
||||||
let graph = self.linearize_graph();
|
|
||||||
|
|
||||||
if let Some(graph) = graph {
|
|
||||||
graph.get_graph_item(&self.inner.current_position).cloned()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_command(&mut self, command: &Commands) -> anyhow::Result<Option<Msg>> {
|
|
||||||
match command {
|
|
||||||
Commands::Archive => {
|
|
||||||
if !self.get_current_path().is_empty() {
|
|
||||||
tracing::debug!("archiving path: {:?}", self.get_current_path())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Commands::CreateSection { name } => {
|
|
||||||
if !name.is_empty() {
|
|
||||||
let mut path = self.get_current_path();
|
|
||||||
path.push(name.replace(" ", "-").replace(".", "-"));
|
|
||||||
|
|
||||||
self.state.commander.execute(
|
|
||||||
hyperlog_core::commander::Command::CreateSection {
|
|
||||||
root: self.inner.root.clone(),
|
|
||||||
path,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Commands::Edit => {
|
|
||||||
if let Some(item) = self.get_current_item() {
|
|
||||||
let path = self.get_current_path();
|
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"found item to edit: path: {}, item: {}",
|
|
||||||
path.join("."),
|
|
||||||
item.name
|
|
||||||
);
|
|
||||||
match item.item_type {
|
|
||||||
GraphItemType::Section => {
|
|
||||||
todo!("cannot edit section at the moment")
|
|
||||||
}
|
|
||||||
GraphItemType::Item { .. } => {
|
|
||||||
if let Some(item) = self.state.querier.get(&self.inner.root, path) {
|
|
||||||
if let GraphItem::Item { .. } = item {
|
|
||||||
return Ok(Some(Msg::OpenEditItemDialog { item }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
self.update_graph()?;
|
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn interact(&mut self) -> anyhow::Result<()> {
|
|
||||||
if !self.get_current_path().is_empty() {
|
|
||||||
tracing::info!("toggling state of items");
|
|
||||||
|
|
||||||
self.state
|
|
||||||
.commander
|
|
||||||
.execute(hyperlog_core::commander::Command::ToggleItem {
|
|
||||||
root: self.inner.root.to_string(),
|
|
||||||
path: self.get_current_path(),
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.update_graph()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> StatefulWidget for GraphExplorer<'a> {
|
|
||||||
type State = GraphExplorerState<'a>;
|
|
||||||
|
|
||||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
|
||||||
let Rect { height, .. } = area;
|
|
||||||
let _height = height as usize;
|
|
||||||
|
|
||||||
if let Some(graph) = &state.graph {
|
|
||||||
let movement_graph: MovementGraph = graph.clone().into();
|
|
||||||
let lines = movement_graph.render_graph(&state.current_position);
|
|
||||||
let para = Paragraph::new(lines);
|
|
||||||
para.render(area, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
244
crates/hyperlog-tui/src/components/graph_explorer.rs
Normal file
244
crates/hyperlog-tui/src/components/graph_explorer.rs
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use hyperlog_core::log::GraphItem;
|
||||||
|
use ratatui::{prelude::*, widgets::*};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
command_parser::Commands, components::movement_graph::GraphItemType, models::Msg,
|
||||||
|
state::SharedState,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::movement_graph::{MovementGraph, MovementGraphItem};
|
||||||
|
use super::render_graph::RenderGraph;
|
||||||
|
|
||||||
|
pub struct GraphExplorer<'a> {
|
||||||
|
state: SharedState,
|
||||||
|
|
||||||
|
pub inner: GraphExplorerState<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GraphExplorerState<'a> {
|
||||||
|
root: String,
|
||||||
|
|
||||||
|
current_path: Option<&'a str>,
|
||||||
|
current_position: Vec<usize>,
|
||||||
|
|
||||||
|
graph: Option<GraphItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> GraphExplorer<'a> {
|
||||||
|
pub fn new(root: String, state: SharedState) -> Self {
|
||||||
|
Self {
|
||||||
|
state,
|
||||||
|
inner: GraphExplorerState::<'a> {
|
||||||
|
root,
|
||||||
|
current_path: None,
|
||||||
|
current_position: Vec::new(),
|
||||||
|
graph: None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_graph(&mut self) -> Result<&mut Self> {
|
||||||
|
let now = std::time::SystemTime::now();
|
||||||
|
|
||||||
|
let graph = self
|
||||||
|
.state
|
||||||
|
.querier
|
||||||
|
.get(
|
||||||
|
&self.inner.root,
|
||||||
|
self.inner
|
||||||
|
.current_path
|
||||||
|
.map(|p| p.split('.').collect::<Vec<_>>())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
.ok_or(anyhow::anyhow!("graph should've had an item"))?;
|
||||||
|
|
||||||
|
self.inner.graph = Some(graph);
|
||||||
|
|
||||||
|
let elapsed = now.elapsed()?;
|
||||||
|
tracing::trace!("Graph.update_graph took: {}nanos", elapsed.as_nanos());
|
||||||
|
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linearize_graph(&self) -> Option<MovementGraph> {
|
||||||
|
self.inner.graph.clone().map(|g| g.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Will only incrmeent to the next level
|
||||||
|
///
|
||||||
|
/// Current: 0.1.0
|
||||||
|
/// Available: 0.1.0.[0,1,2]
|
||||||
|
/// Choses: 0.1.0.0 else nothing
|
||||||
|
pub(crate) fn move_right(&mut self) -> Result<()> {
|
||||||
|
if let Some(graph) = self.linearize_graph() {
|
||||||
|
tracing::debug!("graph: {:?}", graph);
|
||||||
|
let position_items = &self.inner.current_position;
|
||||||
|
|
||||||
|
if let Some(next_item) = graph.next_right(position_items) {
|
||||||
|
self.inner.current_position.push(next_item.index);
|
||||||
|
tracing::trace!("found next item: {:?}", self.inner.current_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Will only incrmeent to the next level
|
||||||
|
///
|
||||||
|
/// Current: 0.1.0
|
||||||
|
/// Available: 0.[0,1,2].0
|
||||||
|
/// Choses: 0.1 else nothing
|
||||||
|
pub(crate) fn move_left(&mut self) -> Result<()> {
|
||||||
|
if let Some(last) = self.inner.current_position.pop() {
|
||||||
|
tracing::trace!(
|
||||||
|
"found last item: {:?}, popped: {}",
|
||||||
|
self.inner.current_position,
|
||||||
|
last
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Will move up if a sibling exists, or up to the most common sibling between sections
|
||||||
|
///
|
||||||
|
/// Current: 0.1.1
|
||||||
|
/// Available: 0.[0.[0,1],1.[0,1]]
|
||||||
|
/// Chose: 0.1.0 again 0.0 We don't choose a subitem in the next three instead we just find the most common sibling
|
||||||
|
pub(crate) fn move_up(&mut self) -> Result<()> {
|
||||||
|
if let Some(graph) = self.linearize_graph() {
|
||||||
|
let position_items = &self.inner.current_position;
|
||||||
|
|
||||||
|
if let Some(next_item) = graph.next_up(position_items) {
|
||||||
|
self.inner.current_position = next_item;
|
||||||
|
tracing::trace!("found next up: {:?}", self.inner.current_position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Will move down if a sibling exists, or down to the most common sibling between sections
|
||||||
|
///
|
||||||
|
/// Current: 0.0.0
|
||||||
|
/// Available: 0.[0.[0,1],1.[0,1]]
|
||||||
|
/// Chose: 0.0.1 again 0.1
|
||||||
|
pub(crate) fn move_down(&mut self) -> Result<()> {
|
||||||
|
if let Some(graph) = self.linearize_graph() {
|
||||||
|
let position_items = &self.inner.current_position;
|
||||||
|
|
||||||
|
if let Some(next_item) = graph.next_down(position_items) {
|
||||||
|
self.inner.current_position = next_item;
|
||||||
|
tracing::trace!("found next down: {:?}", self.inner.current_position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_current_path(&self) -> Vec<String> {
|
||||||
|
let graph = self.linearize_graph();
|
||||||
|
let position_items = &self.inner.current_position;
|
||||||
|
|
||||||
|
if let Some(graph) = graph {
|
||||||
|
graph.to_current_path(position_items)
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_item(&self) -> Option<MovementGraphItem> {
|
||||||
|
let graph = self.linearize_graph();
|
||||||
|
|
||||||
|
if let Some(graph) = graph {
|
||||||
|
graph.get_graph_item(&self.inner.current_position).cloned()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_command(&mut self, command: &Commands) -> anyhow::Result<Option<Msg>> {
|
||||||
|
match command {
|
||||||
|
Commands::Archive => {
|
||||||
|
if !self.get_current_path().is_empty() {
|
||||||
|
tracing::debug!("archiving path: {:?}", self.get_current_path())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Commands::CreateSection { name } => {
|
||||||
|
if !name.is_empty() {
|
||||||
|
let mut path = self.get_current_path();
|
||||||
|
path.push(name.replace(" ", "-").replace(".", "-"));
|
||||||
|
|
||||||
|
self.state.commander.execute(
|
||||||
|
hyperlog_core::commander::Command::CreateSection {
|
||||||
|
root: self.inner.root.clone(),
|
||||||
|
path,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Commands::Edit => {
|
||||||
|
if let Some(item) = self.get_current_item() {
|
||||||
|
let path = self.get_current_path();
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"found item to edit: path: {}, item: {}",
|
||||||
|
path.join("."),
|
||||||
|
item.name
|
||||||
|
);
|
||||||
|
match item.item_type {
|
||||||
|
GraphItemType::Section => {
|
||||||
|
todo!("cannot edit section at the moment")
|
||||||
|
}
|
||||||
|
GraphItemType::Item { .. } => {
|
||||||
|
if let Some(item) = self.state.querier.get(&self.inner.root, path) {
|
||||||
|
if let GraphItem::Item { .. } = item {
|
||||||
|
return Ok(Some(Msg::OpenEditItemDialog { item }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_graph()?;
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn interact(&mut self) -> anyhow::Result<()> {
|
||||||
|
if !self.get_current_path().is_empty() {
|
||||||
|
tracing::info!("toggling state of items");
|
||||||
|
|
||||||
|
self.state
|
||||||
|
.commander
|
||||||
|
.execute(hyperlog_core::commander::Command::ToggleItem {
|
||||||
|
root: self.inner.root.to_string(),
|
||||||
|
path: self.get_current_path(),
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_graph()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StatefulWidget for GraphExplorer<'a> {
|
||||||
|
type State = GraphExplorerState<'a>;
|
||||||
|
|
||||||
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||||
|
let Rect { height, .. } = area;
|
||||||
|
let _height = height as usize;
|
||||||
|
|
||||||
|
if let Some(graph) = &state.graph {
|
||||||
|
let movement_graph: MovementGraph = graph.clone().into();
|
||||||
|
let lines = movement_graph.render_graph(&state.current_position);
|
||||||
|
let para = Paragraph::new(lines);
|
||||||
|
para.render(area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,143 +1,8 @@
|
|||||||
use ratatui::prelude::*;
|
use ratatui::prelude::*;
|
||||||
|
|
||||||
use super::movement_graph::{GraphItemType, MovementGraph};
|
|
||||||
|
|
||||||
pub trait RenderGraph {
|
pub trait RenderGraph {
|
||||||
fn render_graph(&self, items: &[usize]) -> Vec<Line>;
|
fn render_graph(&self, items: &[usize]) -> Vec<Line>;
|
||||||
fn render_graph_spans(&self, items: &[usize]) -> Vec<Vec<Span>>;
|
fn render_graph_spans(&self, items: &[usize]) -> Vec<Vec<Span>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderGraph for MovementGraph {
|
pub mod classic;
|
||||||
/// render_graph takes each level of items, renders them, and finally renders a strongly set selector for the current item the user is on
|
|
||||||
/// This is done from buttom up, and composed via. string padding
|
|
||||||
fn render_graph(&self, items: &[usize]) -> Vec<Line> {
|
|
||||||
// Gets the inner content of the strings
|
|
||||||
|
|
||||||
let mut lines = Vec::new();
|
|
||||||
|
|
||||||
for item in &self.items {
|
|
||||||
let prefix = match item.item_type {
|
|
||||||
GraphItemType::Section => "- ",
|
|
||||||
GraphItemType::Item { done } => {
|
|
||||||
if done {
|
|
||||||
"- [x]"
|
|
||||||
} else {
|
|
||||||
"- [ ]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match items.split_first().map(|(first, rest)| {
|
|
||||||
if item.index == *first {
|
|
||||||
(true, rest)
|
|
||||||
} else {
|
|
||||||
(false, rest)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Some((true, rest)) => {
|
|
||||||
if rest.is_empty() {
|
|
||||||
lines.push(
|
|
||||||
Line::raw(format!("{} {}", prefix, item.name))
|
|
||||||
.style(Style::new().bold().white()),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
lines.push(
|
|
||||||
Line::raw(format!("{} {}", prefix, item.name))
|
|
||||||
.patch_style(Style::new().dark_gray()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.push("".into());
|
|
||||||
|
|
||||||
let embedded_sections = item.values.render_graph_spans(rest);
|
|
||||||
for section in &embedded_sections {
|
|
||||||
let mut line = vec![Span::raw(" ".repeat(4))];
|
|
||||||
line.extend_from_slice(section);
|
|
||||||
lines.push(Line::from(line));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
lines.push(
|
|
||||||
Line::raw(format!("{} {}", prefix, item.name))
|
|
||||||
.patch_style(Style::new().dark_gray()),
|
|
||||||
);
|
|
||||||
|
|
||||||
lines.push("".into());
|
|
||||||
|
|
||||||
let embedded_sections = item.values.render_graph_spans(&[]);
|
|
||||||
for section in &embedded_sections {
|
|
||||||
let mut line = vec![Span::raw(" ".repeat(4))];
|
|
||||||
line.extend_from_slice(section);
|
|
||||||
lines.push(Line::from(line));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lines
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_graph_spans(&self, items: &[usize]) -> Vec<Vec<Span>> {
|
|
||||||
let mut lines = Vec::new();
|
|
||||||
|
|
||||||
for item in &self.items {
|
|
||||||
let prefix = match item.item_type {
|
|
||||||
GraphItemType::Section => "-",
|
|
||||||
GraphItemType::Item { done } => {
|
|
||||||
if done {
|
|
||||||
"- [x]"
|
|
||||||
} else {
|
|
||||||
"- [ ]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match items.split_first().map(|(first, rest)| {
|
|
||||||
if item.index == *first {
|
|
||||||
(true, rest)
|
|
||||||
} else {
|
|
||||||
(false, rest)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Some((true, rest)) => {
|
|
||||||
let mut line = Vec::new();
|
|
||||||
if rest.is_empty() {
|
|
||||||
line.push(
|
|
||||||
Span::raw(format!("{} {}", prefix, item.name))
|
|
||||||
.style(Style::new().bold().white()),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
line.push(
|
|
||||||
Span::raw(format!("{} {}", prefix, item.name))
|
|
||||||
.patch_style(Style::new().dark_gray()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.push(line);
|
|
||||||
lines.push(vec!["".into()]);
|
|
||||||
|
|
||||||
let embedded_sections = item.values.render_graph_spans(rest);
|
|
||||||
for section in &embedded_sections {
|
|
||||||
let mut line = vec![Span::raw(" ".repeat(4))];
|
|
||||||
line.extend_from_slice(section);
|
|
||||||
lines.push(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
lines.push(vec![Span::raw(format!("{prefix} {}", item.name))
|
|
||||||
.patch_style(Style::new().dark_gray())]);
|
|
||||||
|
|
||||||
lines.push(vec!["".into()]);
|
|
||||||
|
|
||||||
let embedded_sections = item.values.render_graph_spans(&[]);
|
|
||||||
for section in &embedded_sections {
|
|
||||||
let mut line = vec![Span::raw(" ".repeat(4))];
|
|
||||||
line.extend_from_slice(section);
|
|
||||||
lines.push(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lines
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
140
crates/hyperlog-tui/src/components/render_graph/classic.rs
Normal file
140
crates/hyperlog-tui/src/components/render_graph/classic.rs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
use ratatui::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::movement_graph::{GraphItemType, MovementGraph};
|
||||||
|
|
||||||
|
use super::RenderGraph;
|
||||||
|
|
||||||
|
impl RenderGraph for MovementGraph {
|
||||||
|
/// render_graph takes each level of items, renders them, and finally renders a strongly set selector for the current item the user is on
|
||||||
|
/// This is done from buttom up, and composed via. string padding
|
||||||
|
fn render_graph(&self, items: &[usize]) -> Vec<Line> {
|
||||||
|
// Gets the inner content of the strings
|
||||||
|
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
|
for item in &self.items {
|
||||||
|
let prefix = match item.item_type {
|
||||||
|
GraphItemType::Section => "- ",
|
||||||
|
GraphItemType::Item { done } => {
|
||||||
|
if done {
|
||||||
|
"- [x]"
|
||||||
|
} else {
|
||||||
|
"- [ ]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match items.split_first().map(|(first, rest)| {
|
||||||
|
if item.index == *first {
|
||||||
|
(true, rest)
|
||||||
|
} else {
|
||||||
|
(false, rest)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Some((true, rest)) => {
|
||||||
|
if rest.is_empty() {
|
||||||
|
lines.push(
|
||||||
|
Line::raw(format!("{} {}", prefix, item.name))
|
||||||
|
.style(Style::new().bold().white()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
lines.push(
|
||||||
|
Line::raw(format!("{} {}", prefix, item.name))
|
||||||
|
.patch_style(Style::new().dark_gray()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push("".into());
|
||||||
|
|
||||||
|
let embedded_sections = item.values.render_graph_spans(rest);
|
||||||
|
for section in &embedded_sections {
|
||||||
|
let mut line = vec![Span::raw(" ".repeat(4))];
|
||||||
|
line.extend_from_slice(section);
|
||||||
|
lines.push(Line::from(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
lines.push(
|
||||||
|
Line::raw(format!("{} {}", prefix, item.name))
|
||||||
|
.patch_style(Style::new().dark_gray()),
|
||||||
|
);
|
||||||
|
|
||||||
|
lines.push("".into());
|
||||||
|
|
||||||
|
let embedded_sections = item.values.render_graph_spans(&[]);
|
||||||
|
for section in &embedded_sections {
|
||||||
|
let mut line = vec![Span::raw(" ".repeat(4))];
|
||||||
|
line.extend_from_slice(section);
|
||||||
|
lines.push(Line::from(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lines
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_graph_spans(&self, items: &[usize]) -> Vec<Vec<Span>> {
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
|
for item in &self.items {
|
||||||
|
let prefix = match item.item_type {
|
||||||
|
GraphItemType::Section => "-",
|
||||||
|
GraphItemType::Item { done } => {
|
||||||
|
if done {
|
||||||
|
"- [x]"
|
||||||
|
} else {
|
||||||
|
"- [ ]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match items.split_first().map(|(first, rest)| {
|
||||||
|
if item.index == *first {
|
||||||
|
(true, rest)
|
||||||
|
} else {
|
||||||
|
(false, rest)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Some((true, rest)) => {
|
||||||
|
let mut line = Vec::new();
|
||||||
|
if rest.is_empty() {
|
||||||
|
line.push(
|
||||||
|
Span::raw(format!("{} {}", prefix, item.name))
|
||||||
|
.style(Style::new().bold().white()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
line.push(
|
||||||
|
Span::raw(format!("{} {}", prefix, item.name))
|
||||||
|
.patch_style(Style::new().dark_gray()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push(line);
|
||||||
|
lines.push(vec!["".into()]);
|
||||||
|
|
||||||
|
let embedded_sections = item.values.render_graph_spans(rest);
|
||||||
|
for section in &embedded_sections {
|
||||||
|
let mut line = vec![Span::raw(" ".repeat(4))];
|
||||||
|
line.extend_from_slice(section);
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
lines.push(vec![Span::raw(format!("{prefix} {}", item.name))
|
||||||
|
.patch_style(Style::new().dark_gray())]);
|
||||||
|
|
||||||
|
lines.push(vec!["".into()]);
|
||||||
|
|
||||||
|
let embedded_sections = item.values.render_graph_spans(&[]);
|
||||||
|
for section in &embedded_sections {
|
||||||
|
let mut line = vec![Span::raw(" ".repeat(4))];
|
||||||
|
line.extend_from_slice(section);
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lines
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user