Skip to content

Commit

Permalink
lints, typo, internalized list mode state
Browse files Browse the repository at this point in the history
  • Loading branch information
simonrupf committed Dec 25, 2023
1 parent 868c8af commit 3ec2068
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 54 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
Change Log of Atari Portfolio address file reader
=================================================

Version 0.2.0 / 2023-07-01
Version 0.2.0 / 2023-12-25
--------------------------
- updated dependencies, increased Rust edition & version
- added this Change Log
- added GitHub actions for dependency updates, linting and release builds
- applied lints, corrected typo, internalized list mode state

Version 0.1.0 / 2020-09-20
--------------------------
Expand Down
120 changes: 67 additions & 53 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{env::args, fs::read, io::stdout, process::exit};

use chrono::Local;

use codepage_437::{CP437_CONTROL, BorrowFromCp437};
use codepage_437::{BorrowFromCp437, CP437_CONTROL};

use crossterm::{
event::{self, Event, KeyCode},
Expand All @@ -14,19 +14,20 @@ use tui::{
layout::Rect,
style::{Color, Style},
text::{Span, Text},
widgets::{Block, Borders, BorderType, List, ListItem, ListState, Paragraph},
widgets::{Block, BorderType, Borders, List, ListItem, ListState, Paragraph},
Frame, Terminal,
};

struct Adresses<'a> {
struct Addresses<'a> {
path: String,
addresses: Vec<&'a str>,
headers: Vec<ListItem<'a>>,
is_list_mode: bool,
state: ListState,
}

impl<'a> Adresses<'a> {
pub fn new(path: String, content: &'a str) -> Adresses<'a> {
impl<'a> Addresses<'a> {
pub fn new(path: String, content: &'a str) -> Addresses<'a> {
// content can be zero terminated and ends in a final CR+LF+CR+LF to be trimmed, before we split on that pattern
let addresses: Vec<&str> = content
.trim_matches('\0')
Expand All @@ -38,10 +39,11 @@ impl<'a> Adresses<'a> {
.map(|address| ListItem::new(address.split("\r\n").next().unwrap()))
.collect();
let state = ListState::default();
Adresses {
Addresses {
path,
addresses,
headers,
is_list_mode: true,
state,
}
}
Expand Down Expand Up @@ -80,26 +82,30 @@ impl<'a> Adresses<'a> {
Rect::new(size.x + 2, size.y + 1, size.width - 3, size.height - 2)
}

pub fn draw_list<B: Backend>(&mut self, f: &mut Frame<B>) {
let items = List::new(self.headers.clone())
.style(Style::default().fg(Color::White))
.highlight_style(Style::default().fg(Color::Black).bg(Color::White));
let inner_size = self.draw_block(f);
f.render_stateful_widget(items, inner_size, &mut self.state);
pub fn draw<B: Backend>(&mut self, f: &mut Frame<B>) {
if self.is_list_mode {
let items = List::new(self.headers.clone())
.style(Style::default().fg(Color::White))
.highlight_style(Style::default().fg(Color::Black).bg(Color::White));
let inner_size = self.draw_block(f);
f.render_stateful_widget(items, inner_size, &mut self.state);
} else {
let address = Paragraph::new(Text::from(
self.addresses[match self.state.selected() {
Some(i) => i,
None => {
self.state.select(Some(0));
0
}
}],
));
let inner_size = self.draw_block(f);
f.render_widget(address, inner_size);
}
}

pub fn draw_selected<B: Backend>(&mut self, f: &mut Frame<B>) {
let address = Paragraph::new(Text::from(
self.addresses[match self.state.selected() {
Some(i) => i,
None => {
self.state.select(Some(0));
0
}
}],
));
let inner_size = self.draw_block(f);
f.render_widget(address, inner_size);
pub fn is_list_mode(&mut self) -> bool {
self.is_list_mode
}

pub fn next(&mut self) {
Expand Down Expand Up @@ -129,60 +135,68 @@ impl<'a> Adresses<'a> {
};
self.state.select(Some(i));
}

pub fn toggle_mode(&mut self) {
self.is_list_mode = !self.is_list_mode;
}
}

fn main() {
let path = match args().nth(1) {
Some(path) => path,
None => {
eprintln!("Missing argument: no path to file given");
exit(255);
}
};

let dos_content = match read(path.clone()) {
Ok(content) => content,
Err(error) => {
eprintln!("Error reading file {}", path);
eprintln!("{}", error);
exit(254);
}
};
let utf8_content = String::borrow_from_cp437(&dos_content, &CP437_CONTROL);
let mut addresses = Adresses::new(path, &utf8_content);
let mut is_list_mode = true;
// stores parsed string slices of addresses and descriptions, tracks
// position in the list, draws frame
let mut addresses;
// parsed string, borrowed to addresses for tracking the offsets into it for
// the string slices of addresses and descriptions
let utf8_content;

// closure to drop parsing state is when done
{
let path = match args().nth(1) {
Some(path) => path,
None => {
eprintln!("Missing argument: no path to file given");
exit(255);
}
};

let dos_content = match read(&path) {
Ok(content) => content,
Err(error) => {
eprintln!("Error reading file {}", path);
eprintln!("{}", error);
exit(254);
}
};
utf8_content = String::borrow_from_cp437(&dos_content, &CP437_CONTROL);
addresses = Addresses::new(path, &utf8_content);
}

enable_raw_mode().unwrap(); // prevent key presses reaching stdout
let mut terminal = Terminal::new(CrosstermBackend::new(stdout())).unwrap();
terminal.clear().unwrap();
terminal.draw(|f| addresses.draw_list(f)).unwrap();
terminal.draw(|f| addresses.draw(f)).unwrap();

loop {
if let Event::Key(key) = event::read().unwrap() {
if is_list_mode {
if addresses.is_list_mode() {
match key.code {
KeyCode::Esc => break,
KeyCode::Enter => is_list_mode = !is_list_mode,
KeyCode::Enter => addresses.toggle_mode(),
KeyCode::Down => addresses.next(),
KeyCode::Up => addresses.previous(),
_ => continue,
}
} else {
match key.code {
KeyCode::Esc => is_list_mode = !is_list_mode,
KeyCode::Esc => addresses.toggle_mode(),
KeyCode::PageDown => addresses.next(),
KeyCode::PageUp => addresses.previous(),
_ => continue,
}
}
terminal
.draw(|f| {
// mode might have changed, check it again
if is_list_mode {
addresses.draw_list(f);
} else {
addresses.draw_selected(f);
}
addresses.draw(f);
})
.unwrap();
}
Expand Down

0 comments on commit 3ec2068

Please sign in to comment.