Compare commits
5 Commits
v0.1.0-rc1
...
v0.1.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
| 04058a48f9 | |||
| 37411bf747 | |||
| 5e90fbe0f7 | |||
| 1350e875c5 | |||
| d4f6efd1c0 |
1086
Cargo.lock
generated
1086
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
14
Cargo.toml
14
Cargo.toml
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "improvise"
|
name = "improvise"
|
||||||
version = "0.1.0-rc1"
|
version = "0.1.0-rc2"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
description = "Terminal pivot-table modeling in the spirit of Lotus Improv"
|
description = "Terminal pivot-table modeling in the spirit of Lotus Improv"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
repository = "https://github.com/fiddlerwoaroof/improvise"
|
repository = "https://github.com/fiddlerwoaroof/improvise"
|
||||||
@ -15,17 +15,17 @@ name = "improvise"
|
|||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ratatui = "0.29"
|
ratatui = "0.30"
|
||||||
crossterm = "0.28"
|
crossterm = "0.29"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
thiserror = "1"
|
thiserror = "2"
|
||||||
indexmap = { version = "2", features = ["serde"] }
|
indexmap = { version = "2", features = ["serde"] }
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
unicode-width = "0.2"
|
unicode-width = "^0.2"
|
||||||
dirs = "5"
|
dirs = "6"
|
||||||
csv = "1"
|
csv = "1"
|
||||||
clap = { version = "4.6.0", features = ["derive"] }
|
clap = { version = "4.6.0", features = ["derive"] }
|
||||||
enum_dispatch = "0.3.13"
|
enum_dispatch = "0.3.13"
|
||||||
|
|||||||
18
flake.lock
generated
18
flake.lock
generated
@ -247,11 +247,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774709303,
|
"lastModified": 1775710090,
|
||||||
"narHash": "sha256-D3Q07BbIA2KnTcSXIqqu9P586uWxN74zNoCH3h2ESHg=",
|
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "8110df5ad7abf5d4c0f6fb0f8f978390e77f9685",
|
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -263,11 +263,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_4": {
|
"nixpkgs_4": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774794121,
|
"lastModified": 1744536153,
|
||||||
"narHash": "sha256-gih24b728CK8twDNU7VX9vVYK2tLEXvy9gm/GKq2VeE=",
|
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c397ef6af68c018462d786e1b65384abc472a907",
|
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -316,11 +316,11 @@
|
|||||||
"nixpkgs": "nixpkgs_4"
|
"nixpkgs": "nixpkgs_4"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774926780,
|
"lastModified": 1775877051,
|
||||||
"narHash": "sha256-JMdDYn0F+swYBILlpCeHDbCSyzqkeSGNxZ/Q5J584jM=",
|
"narHash": "sha256-wpSQm2PD/w4uRo2wb8utk0b5hOBkkg/CZ1xICY+qB7M=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "962a0934d0e32f42d1b5e49186f9595f9b178d2d",
|
"rev": "08b4f3633471874c8894632ade1b78d75dbda002",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@ -140,7 +140,7 @@ impl ImportPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create derived date-component categories
|
// Create derived date-component categories
|
||||||
for (_, _, _, ref derived_name) in &date_extractions {
|
for (_, _, _, derived_name) in &date_extractions {
|
||||||
model.add_category(derived_name)?;
|
model.add_category(derived_name)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ impl ImportPipeline {
|
|||||||
coords.push((cat_proposal.field.clone(), v.clone()));
|
coords.push((cat_proposal.field.clone(), v.clone()));
|
||||||
|
|
||||||
// Extract date components from this field's value
|
// Extract date components from this field's value
|
||||||
for (field, fmt, comp, ref derived_name) in &date_extractions {
|
for (field, fmt, comp, derived_name) in &date_extractions {
|
||||||
if *field == cat_proposal.field {
|
if *field == cat_proposal.field {
|
||||||
if let Some(derived_val) = extract_date_component(&v, fmt, *comp) {
|
if let Some(derived_val) = extract_date_component(&v, fmt, *comp) {
|
||||||
if let Some(cat) = model.category_mut(derived_name) {
|
if let Some(cat) = model.category_mut(derived_name) {
|
||||||
|
|||||||
@ -371,7 +371,7 @@ fn run_headless_script(script_path: &PathBuf, file: &Option<PathBuf>) -> Result<
|
|||||||
// ── Helpers ──────────────────────────────────────────────────────────────────
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
fn get_initial_model(file_path: &Option<PathBuf>) -> Result<Model> {
|
fn get_initial_model(file_path: &Option<PathBuf>) -> Result<Model> {
|
||||||
if let Some(ref path) = file_path {
|
if let Some(path) = file_path {
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
let mut m = persistence::load(path)
|
let mut m = persistence::load(path)
|
||||||
.with_context(|| format!("Failed to load {}", path.display()))?;
|
.with_context(|| format!("Failed to load {}", path.display()))?;
|
||||||
|
|||||||
@ -2118,7 +2118,7 @@ mod parser_edge_cases {
|
|||||||
// files. The generator and parser share a single source of truth: the grammar.
|
// files. The generator and parser share a single source of truth: the grammar.
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod gen {
|
mod generator {
|
||||||
use pest_meta::ast::{Expr, RuleType};
|
use pest_meta::ast::{Expr, RuleType};
|
||||||
use pest_meta::parser;
|
use pest_meta::parser;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
@ -2253,15 +2253,15 @@ mod gen {
|
|||||||
// Use random bytes as entropy for choices in the grammar walk
|
// Use random bytes as entropy for choices in the grammar walk
|
||||||
prop::collection::vec(any::<u8>(), 64..=256).prop_map(|choices| {
|
prop::collection::vec(any::<u8>(), 64..=256).prop_map(|choices| {
|
||||||
let rules = load_grammar();
|
let rules = load_grammar();
|
||||||
let mut gen = Gen::new(&rules, choices);
|
let mut g = Gen::new(&rules, choices);
|
||||||
gen.generate("file")
|
g.generate("file")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod grammar_prop_tests {
|
mod grammar_prop_tests {
|
||||||
use super::{format_md, gen, parse_md};
|
use super::{format_md, generator, parse_md};
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
@ -2269,7 +2269,7 @@ mod grammar_prop_tests {
|
|||||||
|
|
||||||
/// parse(generate()) — every generated file parses without error.
|
/// parse(generate()) — every generated file parses without error.
|
||||||
#[test]
|
#[test]
|
||||||
fn generated_file_parses(file in gen::improv_file()) {
|
fn generated_file_parses(file in generator::improv_file()) {
|
||||||
let result = parse_md(&file);
|
let result = parse_md(&file);
|
||||||
prop_assert!(result.is_ok(),
|
prop_assert!(result.is_ok(),
|
||||||
"Generated file failed to parse:\n{}\nError: {}",
|
"Generated file failed to parse:\n{}\nError: {}",
|
||||||
@ -2278,7 +2278,7 @@ mod grammar_prop_tests {
|
|||||||
|
|
||||||
/// parse(print(parse(generate()))) — round-trip through format is stable.
|
/// parse(print(parse(generate()))) — round-trip through format is stable.
|
||||||
#[test]
|
#[test]
|
||||||
fn generated_file_roundtrips(file in gen::improv_file()) {
|
fn generated_file_roundtrips(file in generator::improv_file()) {
|
||||||
let result1 = parse_md(&file);
|
let result1 = parse_md(&file);
|
||||||
// Skip inputs that don't parse (the grammar walk may produce
|
// Skip inputs that don't parse (the grammar walk may produce
|
||||||
// degenerate inputs like empty model names)
|
// degenerate inputs like empty model names)
|
||||||
|
|||||||
@ -121,7 +121,7 @@ impl View {
|
|||||||
pub fn categories_on(&self, axis: Axis) -> Vec<&str> {
|
pub fn categories_on(&self, axis: Axis) -> Vec<&str> {
|
||||||
self.category_axes
|
self.category_axes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, &a)| a == axis)
|
.filter(|&(_, &a)| a == axis)
|
||||||
.map(|(n, _)| n.as_str())
|
.map(|(n, _)| n.as_str())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user