mirror of
https://github.com/zaphar/sheetsui.git
synced 2025-07-23 05:19:48 -04:00
feat: The beginnings of a reactive table datamodel
This commit is contained in:
parent
3d2bfc79fb
commit
507fa630d5
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "a1"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8470e27ace1e4691e30b3c05a719397c10e799d3ed1814dad8d6797580d9ddd"
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.18"
|
||||
@ -425,6 +431,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
name = "sheetui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"a1",
|
||||
"clap",
|
||||
"crossterm",
|
||||
"ratatui",
|
||||
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
a1 = "1.0.1"
|
||||
clap = { version = "4.5.20", features = ["derive"] }
|
||||
crossterm = "0.28.1"
|
||||
ratatui = "0.29.0"
|
||||
|
24
src/main.rs
24
src/main.rs
@ -5,9 +5,12 @@ use crossterm::event::{self, Event, KeyCode, KeyEventKind};
|
||||
use ratatui::{
|
||||
self,
|
||||
layout::{Constraint, Layout},
|
||||
widgets::{Cell, Row, Table, Tabs},
|
||||
widgets::{Table, Tabs},
|
||||
Frame,
|
||||
};
|
||||
use sheet::{Address, Computable, Tbl};
|
||||
|
||||
mod sheet;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
@ -27,20 +30,17 @@ fn run(terminal: &mut ratatui::DefaultTerminal) -> std::io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_default_rows<'a>(row_count: usize, col_count: usize) -> Vec<Row<'a>> {
|
||||
(0..row_count)
|
||||
.map(|ri| {
|
||||
(0..col_count)
|
||||
.map(|ci| Cell::new(format!(" {}:{} ", ri, ci)))
|
||||
.collect::<Row>()
|
||||
.height(2)
|
||||
})
|
||||
.collect::<Vec<Row>>()
|
||||
fn generate_default_table<'a>() -> Table<'a> {
|
||||
let mut tbl = Tbl::new();
|
||||
tbl.update_entry(Address::new(5, 5), Computable::Text("loc: 5, 5".to_owned()));
|
||||
tbl.update_entry(Address::new(10, 10), Computable::Number(10.10));
|
||||
tbl.update_entry(Address::new(0, 0), Computable::Formula("".to_owned()));
|
||||
tbl.into()
|
||||
}
|
||||
|
||||
fn draw(frame: &mut Frame) {
|
||||
use Constraint::{Min, Percentage};
|
||||
let table = Table::default().rows(generate_default_rows(10, 10));
|
||||
let table = generate_default_table();
|
||||
let tabs = Tabs::new(vec!["sheet1"]).select(0);
|
||||
let rects = Layout::vertical([Min(1), Percentage(90)]).split(frame.area());
|
||||
|
||||
@ -49,7 +49,7 @@ fn draw(frame: &mut Frame) {
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let args = Args::parse();
|
||||
let _ = Args::parse();
|
||||
|
||||
let mut terminal = ratatui::init();
|
||||
terminal.clear()?;
|
||||
|
94
src/sheet/mod.rs
Normal file
94
src/sheet/mod.rs
Normal file
@ -0,0 +1,94 @@
|
||||
//! DataModel for a SpreadSheet
|
||||
//!
|
||||
//! # Overview
|
||||
//!
|
||||
//! Sheets can contain a [Tbl]. Tbl's contain a collection of [Address] to [Computable]
|
||||
//! associations. From this we can compute the dimensions of a Tbl as well as render
|
||||
//! them into a [Table] Widget.
|
||||
|
||||
use ratatui::widgets::{Cell, Row, Table};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// The Address in a [Tbl].
|
||||
#[derive(Default, Debug, PartialEq, PartialOrd, Ord, Eq)]
|
||||
pub struct Address {
|
||||
row: usize,
|
||||
col: usize,
|
||||
}
|
||||
|
||||
impl Address {
|
||||
pub fn new(row: usize, col: usize) -> Self {
|
||||
Self { row, col }
|
||||
}
|
||||
}
|
||||
|
||||
/// The computable value located at an [Address].
|
||||
#[derive(Debug)]
|
||||
pub enum Computable {
|
||||
Text(String),
|
||||
Number(f64),
|
||||
Formula(String),
|
||||
}
|
||||
|
||||
impl Default for Computable {
|
||||
fn default() -> Self {
|
||||
Self::Text("".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
/// A single table of addressable computable values.
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Tbl {
|
||||
addresses: BTreeMap<Address, Computable>,
|
||||
}
|
||||
|
||||
impl Tbl {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn dimensions(&self) -> (usize, usize) {
|
||||
let (mut row, mut col) = (0, 0);
|
||||
for (addr, _) in &self.addresses {
|
||||
row = std::cmp::max(row, addr.row);
|
||||
col = std::cmp::max(col, addr.col);
|
||||
}
|
||||
(row, col)
|
||||
}
|
||||
|
||||
pub fn get_computable(&self, row: usize, col: usize) -> Option<&Computable> {
|
||||
self.addresses.get(&Address::new(row, col))
|
||||
}
|
||||
|
||||
pub fn update_entry(&mut self, address: Address, computable: Computable) {
|
||||
// TODO(zaphar): At some point we'll need to store the graph of computation
|
||||
// dependencies
|
||||
self.addresses.insert(address, computable);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t> From<Tbl> for Table<'t> {
|
||||
fn from(value: Tbl) -> Self {
|
||||
let (row, col) = value.dimensions();
|
||||
let rows = (0..=row)
|
||||
.map(|ri| {
|
||||
(0..=col)
|
||||
.map(|ci| {
|
||||
match value.get_computable(ri, ci) {
|
||||
// TODO(zaphar): Style information
|
||||
Some(Computable::Text(s)) => Cell::new(format!(" {}", s)),
|
||||
Some(Computable::Number(f)) => Cell::new(format!(" {}", f)),
|
||||
Some(Computable::Formula(_expr)) => Cell::new(format!(" .formula. ")),
|
||||
None => Cell::new(format!(" {}:{} ", ri, ci)),
|
||||
}
|
||||
})
|
||||
.collect::<Row>()
|
||||
})
|
||||
.collect::<Vec<Row>>();
|
||||
Table::default().rows(rows)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
12
src/sheet/tests.rs
Normal file
12
src/sheet/tests.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_dimensions_calculation() {
|
||||
let mut tbl = Tbl::new();
|
||||
tbl.update_entry(Address::new(0, 0), Computable::Text(String::new()));
|
||||
assert_eq!((0, 0), tbl.dimensions());
|
||||
tbl.update_entry(Address::new(0, 10), Computable::Text(String::new()));
|
||||
assert_eq!((0, 10), tbl.dimensions());
|
||||
tbl.update_entry(Address::new(20, 5), Computable::Text(String::new()));
|
||||
assert_eq!((20, 10), tbl.dimensions());
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user