aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjakobst1n <jakob.stendahl@outlook.com>2024-06-11 21:56:34 +0200
committerjakobst1n <jakob.stendahl@outlook.com>2024-06-11 21:56:34 +0200
commitaac665d8012c0521f5ca7ced8167984922f21c7c (patch)
tree48ce6d3b17eaa71446ff6fd6db2d945eceb1ac6a
parent12d98b326369d8af56d690a86ce82f862026a701 (diff)
downloadtextgraph-aac665d8012c0521f5ca7ced8167984922f21c7c.tar.gz
textgraph-aac665d8012c0521f5ca7ced8167984922f21c7c.zip
Refactor the code, deletions will follow
-rw-r--r--src/graph.rs460
-rw-r--r--src/lib.rs1
-rw-r--r--src/main.rs33
-rw-r--r--src/parseopts.rs79
4 files changed, 354 insertions, 219 deletions
diff --git a/src/graph.rs b/src/graph.rs
index fd616ea..52e332c 100644
--- a/src/graph.rs
+++ b/src/graph.rs
@@ -1,4 +1,5 @@
-use crate::graph_canvas::{GraphCanvas, GraphPixel};
+//use std::io::IsTerminal;
+//dbg!(std::io::stdout().is_terminal());
const ASCII_0: char = '─';
const ASCII_1: char = '│';
@@ -7,193 +8,332 @@ const ASCII_3: char = '╰';
const ASCII_4: char = '╮';
const ASCII_7: char = '╯';
-#[derive(Debug)]
-pub struct GraphOptions {
- pub width: u64,
- pub height: u64,
- pub interpolate: bool,
- pub axis: bool,
+#[derive(Clone)]
+#[allow(dead_code)]
+enum GraphPixel<T> {
+ Normal(T),
+ Green(T),
+ Blue(T),
+ Red(T),
+ Blank,
}
-/// Simply downsample, not the most correct way, but will likely not be too bad.
-///
-/// # Arguments
-///
-/// * `y_values` - The y values that should be downsampled
-/// * `column_count` - Desired resolution of the output
-pub fn downsample(y_values: &[f64], column_count: usize) -> Vec<f64> {
- let factor = y_values.len() as f64 / column_count as f64;
- (0..column_count)
- .map(|i| y_values[(i as f64 * factor) as usize])
- .collect()
+impl<T> std::default::Default for GraphPixel<T> {
+ fn default() -> Self {
+ GraphPixel::Blank
+ }
}
-/// A better way to downsize, heavier and more complex, but should be used when sample speed is uneven.
-///
-/// # Arguments
-///
-/// * `y_values` - The y values that should be downsampled
-/// * `x_values` - X values, needed to interpolate while keeping sample distance
-/// * `column_count` - Desired resolution of the output
-pub fn interpolate(y_values: &[f64], x_values: &[f64], column_count: usize) -> Vec<f64> {
- let min_x = x_values.iter().cloned().fold(f64::INFINITY, f64::min);
- let max_x = x_values.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
- let step = (max_x - min_x) / (column_count as f64 - 1.0);
- let mut interpolated_data = Vec::new();
-
- for i in 0..column_count {
- let target_mark = min_x + i as f64 * step;
- let mut j = 0;
- while j < x_values.len() - 1 && x_values[j + 1] < target_mark {
- j += 1;
- }
- let t0 = x_values[j];
- let t1 = x_values[j + 1];
- let d0 = y_values[j];
- let d1 = y_values[j + 1];
- let value = d0 + (d1 - d0) * (target_mark - t0) / (t1 - t0);
- interpolated_data.push(value);
+impl<T: std::fmt::Display> std::fmt::Display for GraphPixel<T> {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ GraphPixel::Normal(c) => format!("{}", c),
+ GraphPixel::Green(c) => format!("\x1b[32m{}\x1b[0m", c),
+ GraphPixel::Blue(c) => format!("\x1b[33m{}\x1b[0m", c),
+ GraphPixel::Red(c) => format!("\x1b[31m{}\x1b[0m", c),
+ GraphPixel::Blank => String::from(" "),
+ }
+ )
}
+}
- interpolated_data
+/// Available options for how the graph should look
+#[derive(Clone)]
+pub enum GraphType {
+ /// Use only * symbols
+ Star,
+ /// Use pretty characters from the ascii range
+ Ascii,
}
-/// Scale a value to a new scale, useful for y values which needs to be scaled to fit within a size
-///
-/// # Arguments
-///
-/// * `values` - The values to scale to a new height
-/// * `row_count` - The desired range of the new values (0 -> row_count)
-fn scale(values: &[f64], row_count: usize) -> Vec<usize> {
- let min_value = values.iter().cloned().fold(f64::INFINITY, f64::min);
- let max_value = values.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
- let scale_factor = (row_count - 1) as f64 / (max_value - min_value);
- values
- .iter()
- .map(|&y| ((y - min_value) * scale_factor).round() as usize)
- .collect()
+impl std::default::Default for GraphType {
+ fn default() -> Self {
+ GraphType::Star
+ }
}
-/// Prepare the values of a graph before graphing
-/// by applying scaling and interpolation/downscaling
-///
-/// # Arguments
-///
-/// * `x_values` - Values of the x-axis, needed for interpolation
-/// * `y_values` - Graph values
-/// * `graph` - The graph object, needed for knowing the information about width and height
-/// * `options` - GraphOptions, used for forced interpolation
-pub fn prepare(
- y_values: &[f64],
- x_values: &[f64],
- graph: &GraphCanvas<GraphPixel>,
- options: &GraphOptions,
-) -> Vec<usize> {
- let y_values = if !options.interpolate {
- // && x_values.windows(2).all(|w| w[1] - w[0] == w[0] - w[1]) {
- if y_values.len() >= graph.width() {
- downsample(&y_values, graph.width())
+/// Temporary variables used while building a graph
+#[allow(dead_code)]
+pub struct GraphBuilder {
+ /// A array of pixels, this will ultimately be turned to a string, is initialized to width * height
+ elements: Vec<GraphPixel<char>>,
+ /// Width of canvas
+ width: usize,
+ /// Height of canvas
+ height: usize,
+ /// Width of the area of the canvas left for the actual graph
+ draw_width: usize,
+ /// Height of the area of the canvas left for the actual graph
+ draw_height: usize,
+ /// x-offset for where the graph draw area begins
+ col_offset: usize,
+ /// y-offset for where the graph draw area begins
+ row_offset: usize,
+ /// The values of the x-axis of the graph
+ x_values: Vec<f64>,
+ /// The values of the y-axis of the graph
+ y_values: Vec<f64>,
+ /// Decides whether axis will be drawn on the resulting graph
+ enable_axis: bool,
+ /// Which GraphType to use when the graph is drawn
+ graph_type: GraphType,
+}
+
+impl GraphBuilder {
+ /// Create a new canvas with desired width and height
+ ///
+ /// # Arguments
+ ///
+ /// * `width` - Width of the output canvas
+ /// * `height` - Height of the output canvas
+ pub fn new(x_values: &[f64], y_values: &[f64], width: usize, height: usize) -> Self {
+ GraphBuilder {
+ elements: vec![GraphPixel::default(); width * height],
+ width,
+ height,
+ draw_width: width,
+ draw_height: height,
+ col_offset: 0,
+ row_offset: 0,
+ x_values: x_values.to_vec(),
+ y_values: y_values.to_vec(),
+ enable_axis: false,
+ graph_type: GraphType::default(),
+ }
+ }
+
+ /// Enable or disable axis in output
+ pub fn axis(&mut self, enable_axis: bool) -> &Self {
+ self.enable_axis = enable_axis;
+ self
+ }
+
+ /// Set graph type
+ pub fn graph_type(&mut self, graph_type: GraphType) -> &Self {
+ self.graph_type = graph_type;
+ self
+ }
+
+ /// Build the actual graph,
+ /// this is potentially a heavy operation, and it will mutate &self!
+ /// If you want to only see the "current state", you should clone first!
+ pub fn build(&mut self) -> String {
+ //let min_x = self.x_values.iter().cloned().fold(f64::INFINITY, f64::min);
+ //let max_x = self
+ // .x_values
+ // .iter()
+ // .cloned()
+ // .fold(f64::NEG_INFINITY, f64::max);
+ let min_y = self.y_values.iter().cloned().fold(f64::INFINITY, f64::min);
+ let max_y = self
+ .y_values
+ .iter()
+ .cloned()
+ .fold(f64::NEG_INFINITY, f64::max);
+
+ if self.enable_axis {
+ self.draw_axis(
+ GraphPixel::Normal(ASCII_1),
+ GraphPixel::Normal(ASCII_0),
+ GraphPixel::Normal('└'),
+ GraphPixel::Normal('┌'),
+ GraphPixel::Normal('┘'),
+ GraphPixel::Normal('┐'),
+ );
+ }
+
+ if true {
+ // && x_values.windows(2).all(|w| w[1] - w[0] == w[0] - w[1]) {
+ if self.y_values.len() >= self.draw_width {
+ // Downsample using a common downsampling, this allows us to avoid doing anything
+ // with the x values
+
+ let factor = self.y_values.len() as f64 / self.draw_width as f64;
+ let mut new_values = Vec::with_capacity(self.draw_width);
+ for i in 0..self.draw_width {
+ let new_value = self.y_values[(i as f64 * factor) as usize];
+ new_values.push(new_value);
+ }
+ self.y_values = new_values;
+ }
} else {
- y_values.to_vec()
+ // If the sample size is not consistent, we should interpolate
+ todo!("interpolation is not implemented");
+ //interpolate(&y_values, &x_values, graph.width())
+ };
+
+ // Scale the data
+ let scale_factor = (self.draw_height - 1) as f64 / (max_y - min_y);
+ for i in 0..self.y_values.len() {
+ self.y_values[i] = ((self.y_values[i] - min_y) * scale_factor).round();
}
- } else {
- interpolate(&y_values, &x_values, graph.width())
- };
- let scaled_data = scale(&y_values, graph.height());
- scaled_data
-}
+ match self.graph_type {
+ GraphType::Star => self.draw_star(),
+ GraphType::Ascii => self.draw_ascii(),
+ }
-/// Draw a graph using * for the pixels of the graph
-///
-/// # Arguments
-///
-/// * `x_values` - Values of the x-axis
-/// * `y_values` - Graph values
-/// * `options` - GraphOptions, used for forced interpolation
-pub fn star(y_values: &[f64], x_values: &[f64], options: &GraphOptions) -> String {
- let mut graph = GraphCanvas::new(options.width as usize, options.height as usize);
- if options.axis {
- graph.axis(
- GraphPixel::Normal(ASCII_1),
- GraphPixel::Normal(ASCII_0),
- GraphPixel::Normal('└'),
- GraphPixel::Normal('┌'),
- GraphPixel::Normal('┘'),
- GraphPixel::Normal('┐'),
- );
+ self.to_string()
}
- let y_values = prepare(y_values, x_values, &graph, options);
- for (i, &value) in y_values.iter().enumerate() {
- let y = graph.height() - value - 1;
- graph[(y, i)] = GraphPixel::Normal('*');
+ /// Turn canvas into a string
+ pub fn to_string(&self) -> String {
+ let mut out = String::with_capacity(self.height * (self.width + 1));
+ for (i, px) in self.elements.iter().enumerate() {
+ out.push_str(&px.to_string());
+ if (i + 1) % self.width == 0 && i < (self.height * self.width - 1) {
+ out.push('\n');
+ }
+ }
+ out
}
- graph.to_string()
-}
+ /// Set a pixel at a absolute position in the canvas
+ ///
+ /// # Argument
+ ///
+ /// * `x` - X-position of pixel
+ /// * `y` - Y-position of pixel
+ /// * `px` - The pixel to set
+ fn draw_exact(&mut self, x: usize, y: usize, px: GraphPixel<char>) {
+ let pos = y * self.width + x;
+ self.elements[pos] = px;
+ }
-/// Draw a graph using somewhat pretty ascii characters for pixels of the graph
-///
-/// # Arguments
-///
-/// * `x_values` - Values of the x-axis
-/// * `y_values` - Graph values
-/// * `options` - GraphOptions, used for forced interpolation
-pub fn ascii(y_values: &[f64], x_values: &[f64], options: &GraphOptions) -> String {
- let mut graph = GraphCanvas::new_default(
- GraphPixel::Blank,
- options.width as usize,
- options.height as usize,
- );
- if options.axis {
- graph.axis(
- GraphPixel::Normal(ASCII_1),
- GraphPixel::Normal(ASCII_0),
- GraphPixel::Normal('└'),
- GraphPixel::Normal('┌'),
- GraphPixel::Normal('┘'),
- GraphPixel::Normal('┐'),
- );
+ /// Set a pixel in the drawable part of the canvas
+ ///
+ /// # Argument
+ ///
+ /// * `x` - Relative X-position of pixel
+ /// * `y` - Relative Y-position of pixel
+ /// * `px` - The pixel to set
+ fn draw(&mut self, x: usize, y: usize, px: GraphPixel<char>) {
+ let pos = (y + self.row_offset) * self.width + (x + self.col_offset);
+ self.elements[pos] = px;
}
- let y_values = prepare(y_values, x_values, &graph, options);
- if options.axis {
- graph.set(0, graph.height() - y_values[0], GraphPixel::Green('├'));
- graph.set(
- graph.full_width() - 1,
- graph.height() - y_values[y_values.len() - 1],
- GraphPixel::Green('┤'),
- );
+ /// Add axis to the canvas and move graph drawing area inside axis
+ ///
+ /// # Arguments
+ ///
+ /// * `c1` - Horizontal axis lines
+ /// * `c2` - Vertical axis lines
+ /// * `c4` - Bottom left axis pixel
+ /// * `c5` - Top left axis pixel
+ /// * `c6` - Bottom right axis pixel
+ /// * `c7` - Top right axis pixel
+ fn draw_axis(
+ &mut self,
+ c1: GraphPixel<char>,
+ c2: GraphPixel<char>,
+ c3: GraphPixel<char>,
+ c4: GraphPixel<char>,
+ c5: GraphPixel<char>,
+ c6: GraphPixel<char>,
+ ) {
+ if self.height < 2 || self.width < 2 {
+ return;
+ }
+ for i in 0..self.height {
+ self.elements[i * self.width] = c1.clone();
+ self.elements[i * self.width + self.width - 1] = c1.clone();
+ }
+ for i in 1..self.width - 1 {
+ self.elements[i] = c2.clone();
+ self.elements[(self.height - 1) * self.width + i] = c2.clone();
+ }
+ self.elements[0] = c4.clone();
+ self.elements[self.width - 1] = c6.clone();
+ self.elements[(self.height - 1) * self.width] = c3.clone();
+ self.elements[self.height * self.width - 1] = c5.clone();
+ if self.draw_height > 2 {
+ self.draw_height = self.height - 2;
+ }
+ if self.draw_width > 2 {
+ self.draw_width = self.width - 2;
+ }
+ self.col_offset = 1;
+ self.row_offset = 1;
}
- for i in 0..y_values.len() {
- let y1 = graph.height() - y_values[i] - 1;
- let y2 = if i < y_values.len() - 1 {
- graph.height() - y_values[i + 1] - 1
- } else {
- y1
- };
- if y1 == y2 {
- graph[(y1, i)] = GraphPixel::Green(ASCII_0);
- } else if y1 > y2 {
- graph[(y1, i)] = GraphPixel::Green(ASCII_7);
- graph[(y2, i)] = GraphPixel::Green(ASCII_2);
- for j in (y2 + 1)..y1 {
- graph[(j, i)] = GraphPixel::Green(ASCII_1);
- }
- } else {
- graph[(y1, i)] = GraphPixel::Green(ASCII_4);
- graph[(y2, i)] = GraphPixel::Green(ASCII_3);
- for j in (y1 + 1)..y2 {
- graph[(j, i)] = GraphPixel::Green(ASCII_1);
- }
+ /// Draw a graph using * for the pixels of the graph
+ fn draw_star(&mut self) {
+ for i in 0..self.y_values.len() {
+ let y = self.draw_height - (self.y_values[i] as usize) - 1;
+ self.draw(i, y, GraphPixel::Normal('*'));
}
}
- graph.to_string()
+ /// Draw a graph using somewhat pretty ascii characters for pixels of the graph
+ pub fn draw_ascii(&mut self) {
+ if self.enable_axis {
+ self.draw_exact(0, self.draw_height - self.y_values[0] as usize, GraphPixel::Green('├'));
+ self.draw_exact(
+ self.width - 1,
+ self.height - self.y_values[self.y_values.len() - 1] as usize,
+ GraphPixel::Green('┤'),
+ );
+ }
+ for i in 0..self.y_values.len() {
+ let y1 = self.draw_height - (self.y_values[i] as usize) - 1;
+ let y2 = if i < self.y_values.len() - 1 {
+ self.draw_height - (self.y_values[i + 1] as usize) - 1
+ } else {
+ y1
+ };
+
+ if y1 == y2 {
+ self.draw(i, y1, GraphPixel::Green(ASCII_0));
+ } else if y1 > y2 {
+ self.draw(i, y1, GraphPixel::Green(ASCII_7));
+ self.draw(i, y2, GraphPixel::Green(ASCII_2));
+ for j in (y2 + 1)..y1 {
+ self.draw(i, j, GraphPixel::Green(ASCII_1));
+ }
+ } else {
+ self.draw(i, y1, GraphPixel::Green(ASCII_4));
+ self.draw(i, y2, GraphPixel::Green(ASCII_3));
+ for j in (y1 + 1)..y2 {
+ self.draw(i, j, GraphPixel::Green(ASCII_1));
+ }
+ }
+ }
+ }
}
+// /// A better way to downsize, heavier and more complex, but should be used when sample speed is uneven.
+// ///
+// /// # Arguments
+// ///
+// /// * `y_values` - The y values that should be downsampled
+// /// * `x_values` - X values, needed to interpolate while keeping sample distance
+// /// * `column_count` - Desired resolution of the output
+// pub fn interpolate(y_values: &[f64], x_values: &[f64], column_count: usize) -> Vec<f64> {
+// let min_x = x_values.iter().cloned().fold(f64::INFINITY, f64::min);
+// let max_x = x_values.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
+// let step = (max_x - min_x) / (column_count as f64 - 1.0);
+// let mut interpolated_data = Vec::new();
+//
+// for i in 0..column_count {
+// let target_mark = min_x + i as f64 * step;
+// let mut j = 0;
+// while j < x_values.len() - 1 && x_values[j + 1] < target_mark {
+// j += 1;
+// }
+// let t0 = x_values[j];
+// let t1 = x_values[j + 1];
+// let d0 = y_values[j];
+// let d1 = y_values[j + 1];
+// let value = d0 + (d1 - d0) * (target_mark - t0) / (t1 - t0);
+// interpolated_data.push(value);
+// }
+//
+// interpolated_data
+// }
+
//const _BRAILLE_1: char = '⣿';
//const BRAILLE_1_0: char = '⡀';
//const BRAILLE_1_1: char = '⣀';
diff --git a/src/lib.rs b/src/lib.rs
index 11f9db9..b85ba6f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,3 @@
pub mod graph;
-pub mod graph_canvas;
pub mod parseopts;
pub mod term;
diff --git a/src/main.rs b/src/main.rs
index 49650e1..a8a2786 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
-use textgraph::graph;
-use textgraph::parseopts::{parseopts, Opts};
use std::io::{self, BufRead, Write};
use std::str::FromStr;
+use textgraph::graph;
+use textgraph::parseopts::{parseopts, Opts};
/// Will graph what comes in through stdin,
/// For each new line, the graph will be re-drawn.
@@ -10,7 +10,7 @@ use std::str::FromStr;
///
/// * `opts` - textgraph::parseopts::Opts
fn filter(opts: Opts) {
- print!("\x1b[?1049h");
+ //print!("\x1b[?1049h");
let mut x_values: Vec<f64> = Vec::new();
let mut y_values: Vec<f64> = Vec::new();
@@ -25,18 +25,15 @@ fn filter(opts: Opts) {
y_values.push(y);
x_values.push(i);
- let graph_options: textgraph::graph::GraphOptions = (&opts).into();
- let g = match opts.graph_type {
- textgraph::parseopts::GraphType::Ascii => {
- graph::ascii(&y_values, &x_values, &graph_options)
- }
- textgraph::parseopts::GraphType::Star => graph::star(&y_values, &x_values, &graph_options),
- };
+ let mut gb = graph::GraphBuilder::new(&x_values, &y_values, opts.width, opts.height);
+ gb.axis(opts.axis);
+ gb.graph_type(opts.graph_type.clone());
+
print!("\x1B[2J\x1B[H");
- println!("{}", g);
+ println!("{}", gb.build());
}
- print!("\x1B[?1049l");
+ //print!("\x1B[?1049l");
io::stdout().flush().unwrap();
}
@@ -57,14 +54,10 @@ fn graph_file(opts: Opts) {
x_values.push(i as f64);
}
- let graph_options: textgraph::graph::GraphOptions = (&opts).into();
- let g = match opts.graph_type {
- textgraph::parseopts::GraphType::Ascii => {
- graph::ascii(&y_values, &x_values, &graph_options)
- }
- textgraph::parseopts::GraphType::Star => graph::star(&y_values, &x_values, &graph_options),
- };
- println!("{}", g);
+ let mut gb = graph::GraphBuilder::new(&x_values, &y_values, opts.width, opts.height);
+ gb.axis(opts.axis);
+ gb.graph_type(opts.graph_type);
+ println!("{}", gb.build());
}
/// Main entry point for the binary of textgraph
diff --git a/src/parseopts.rs b/src/parseopts.rs
index a49d02c..5368a87 100644
--- a/src/parseopts.rs
+++ b/src/parseopts.rs
@@ -1,55 +1,61 @@
-use crate::graph::GraphOptions;
+use crate::graph::GraphType;
use std::str::FromStr;
-/// Available options for how the graph should look
-pub enum GraphType {
- /// Use only * symbols
- Star,
- /// Use pretty characters from the ascii range
- Ascii,
+/// Struct containing command line options
+pub struct Opts {
+ /// Desired width of graph, if None, it should be automatically determined
+ pub width: usize,
+ /// Desired height of graph, if None, it should be automatically determined
+ pub height: usize,
+ /// Which type of graph it should be, ascii, star
+ pub graph_type: GraphType,
+ /// Enable axis on the resulting graph, makes it a bit prettier
+ pub axis: bool,
+ /// Specify if it is used as a filter, and you only want to look at the last N samples
+ pub last_n: Option<u64>,
+ /// Read from the specified file, instead of reading continously from stdin
+ pub in_file: Option<String>,
}
/// Struct containing command line options
-pub struct Opts {
+pub struct OptsBuilder {
/// Desired width of graph, if None, it should be automatically determined
- pub width: Option<u64>,
+ pub width: Option<usize>,
/// Desired height of graph, if None, it should be automatically determined
- pub height: Option<u64>,
+ pub height: Option<usize>,
/// Which type of graph it should be, ascii, star
pub graph_type: GraphType,
- /// Wether to always interpolate, even if not nesecarry
- pub interpolate: bool,
/// Enable axis on the resulting graph, makes it a bit prettier
pub axis: bool,
/// Specify if it is used as a filter, and you only want to look at the last N samples
pub last_n: Option<u64>,
- /// Read from the specified file, instead of reading continously from stdin
+ /// Read from the specified file, instead of reading continously from stdin
pub in_file: Option<String>,
}
-impl From<&Opts> for GraphOptions {
- /// Convert from CLIOpts to GraphOptions,
- /// This will do some magic, like find the terminal size if not specified, etc.
- fn from(opts: &Opts) -> Self {
- GraphOptions {
- width: opts.width.unwrap_or_else(|| {
+impl OptsBuilder {
+ fn build(self) -> Opts {
+ Opts {
+ width: self.width.unwrap_or_else(|| {
if let Ok((width, _)) = crate::term::get_terminal_size() {
- width as u64
+ width as usize
} else {
println!("Could not determine TTY columns, specify with -r");
std::process::exit(1);
}
}),
- height: opts.height.unwrap_or_else(|| {
+ height: self.height.unwrap_or_else(|| {
if let Ok((_, height)) = crate::term::get_terminal_size() {
- height as u64 - 1
+ height as usize - 1
} else {
println!("Could not determine TTY rows, specify with -h");
std::process::exit(1);
}
}),
- interpolate: opts.interpolate,
- axis: opts.axis,
+ graph_type: self.graph_type,
+ axis: self.axis,
+ last_n: self.last_n,
+ in_file: self.in_file,
}
}
}
@@ -76,11 +82,8 @@ macro_rules! parseopts_panic {
/// * `value` - Optionally the value of the option/argument. This function will panic if not
/// provided when it is required.
/// * `progname` - The first argument of the program, this is used for error messages.
-pub fn parseopt(opts: &mut Opts, arg: &str, value: Option<String>, progname: &str) {
+pub fn parseopt(opts: &mut OptsBuilder, arg: &str, value: Option<String>, progname: &str) {
match arg {
- "interpolate" => {
- opts.interpolate = true;
- }
"t" => {
let Some(graph_type) = value else {
println!("Missing value for {}", arg);
@@ -107,7 +110,7 @@ pub fn parseopt(opts: &mut Opts, arg: &str, value: Option<String>, progname: &st
println!("Missing value for {}", arg);
parseopts_panic!(progname);
};
- let Ok(height) = u64::from_str(&height) else {
+ let Ok(height) = usize::from_str(&height) else {
println!("Cannot parse integer from \"{}\"", height);
parseopts_panic!(progname);
};
@@ -132,7 +135,7 @@ pub fn parseopt(opts: &mut Opts, arg: &str, value: Option<String>, progname: &st
println!("Missing value for {}", arg);
parseopts_panic!(progname);
};
- let Ok(width) = u64::from_str(&width) else {
+ let Ok(width) = usize::from_str(&width) else {
println!("Cannot parse integer from \"{}\"", width);
parseopts_panic!(progname);
};
@@ -151,11 +154,10 @@ pub fn parseopt(opts: &mut Opts, arg: &str, value: Option<String>, progname: &st
/// This function is specialised for the TextGraph program,
/// but is easily adaptable for other programs as well.
pub fn parseopts() -> Opts {
- let mut opts = Opts {
+ let mut opts = OptsBuilder {
width: None,
height: None,
graph_type: GraphType::Star,
- interpolate: false,
axis: false,
last_n: None,
in_file: None,
@@ -183,7 +185,7 @@ pub fn parseopts() -> Opts {
"widht" | "height" | "last-n" => {
arg_value = it.next();
}
- _ => ()
+ _ => (),
}
}
parseopt(&mut opts, &arg_name, arg_value, &progname);
@@ -203,17 +205,18 @@ pub fn parseopts() -> Opts {
match pos_arg {
0 => {
opts.in_file = Some(arg);
- },
+ }
_ => {
- println!("No positional argument expected at position {} (\"{}\")", pos_arg, arg);
+ println!(
+ "No positional argument expected at position {} (\"{}\")",
+ pos_arg, arg
+ );
parseopts_panic!(progname);
}
}
pos_arg += 1;
}
-
}
-
- return opts;
+ return opts.build();
}