Skip to content

Commit

Permalink
Move buffer history to a new file
Browse files Browse the repository at this point in the history
  • Loading branch information
YS-L committed Jan 1, 2024
1 parent 75a4fe0 commit c51f94b
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 102 deletions.
18 changes: 18 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::fmt;

#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
pub enum InputMode {
Default,
GotoLine,
Find,
Filter,
FilterColumns,
Option,
Help,
}

impl fmt::Display for InputMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
145 changes: 145 additions & 0 deletions src/history.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use crate::common::InputMode;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;

pub struct BufferHistory {
buffers: Vec<String>,
cursor: usize,
}

impl BufferHistory {
fn new_with(buf: &str) -> Self {
BufferHistory {
buffers: vec![buf.to_string()],
cursor: 1,
}
}

fn push(&mut self, buf: &str) {
if buf.is_empty() {
// Don't keep empty entries
return;
}
if let Some(index) = self.buffers.iter().position(|x| x == buf) {
// Don't keep duplicate entries
self.buffers.remove(index);
}
self.buffers.push(buf.to_string());
self.reset_cursor();
}

fn prev(&mut self) -> Option<String> {
if self.cursor == 0 {
return None;
}
self.cursor = self.cursor.saturating_sub(1);
Some(self.buffers[self.cursor].clone())
}

fn next(&mut self) -> Option<String> {
if self.cursor >= self.buffers.len() - 1 {
return None;
}
self.cursor = self.cursor.saturating_add(1);
Some(self.buffers[self.cursor].clone())
}

fn reset_cursor(&mut self) {
self.cursor = self.buffers.len();
}
}

pub struct BufferHistoryContainer {
inner: HashMap<InputMode, BufferHistory>,
}

impl BufferHistoryContainer {
pub fn new() -> Self {
BufferHistoryContainer {
inner: HashMap::new(),
}
}

pub fn set(&mut self, input_mode: InputMode, content: &str) {
match self.inner.entry(input_mode) {
Occupied(mut e) => {
e.get_mut().push(content);
}
Vacant(e) => {
e.insert(BufferHistory::new_with(content));
}
}
}

pub fn prev(&mut self, input_mode: InputMode) -> Option<String> {
self.inner
.get_mut(&input_mode)
.and_then(|history| history.prev())
}

pub fn next(&mut self, input_mode: InputMode) -> Option<String> {
self.inner
.get_mut(&input_mode)
.and_then(|history| history.next())
}

pub fn reset_cursors(&mut self) {
for (_, history) in self.inner.iter_mut() {
history.reset_cursor();
}
}
}

#[cfg(test)]
mod tests {

use super::*;

#[test]
fn test_prev_next() {
let mut history = BufferHistory::new_with("foo");
history.push("bar");
history.push("baz");
history.push("foo");
assert_eq!(history.prev(), Some("foo".to_string()));
assert_eq!(history.prev(), Some("baz".to_string()));
assert_eq!(history.prev(), Some("bar".to_string()));
assert_eq!(history.prev(), None);
assert_eq!(history.prev(), None);
assert_eq!(history.next(), Some("baz".to_string()));
assert_eq!(history.next(), Some("foo".to_string()));
assert_eq!(history.next(), None);
assert_eq!(history.next(), None);
}

#[test]
fn test_push_duplicate() {
let mut history = BufferHistory::new_with("foo");
history.push("bar");
history.push("baz");
history.push("foo");
history.push("bar");
assert_eq!(history.prev(), Some("bar".to_string()));
assert_eq!(history.prev(), Some("foo".to_string()));
assert_eq!(history.prev(), Some("baz".to_string()));
assert_eq!(history.prev(), None);
}

#[test]
fn test_container() {
let mut history_container = BufferHistoryContainer::new();
history_container.set(InputMode::Find, "foo");
history_container.set(InputMode::Find, "bar");
history_container.set(InputMode::GotoLine, "123");
history_container.set(InputMode::GotoLine, "456");
assert_eq!(history_container.prev(InputMode::Default), None);
assert_eq!(
history_container.prev(InputMode::Find),
Some("bar".to_string())
);
assert_eq!(
history_container.prev(InputMode::GotoLine),
Some("456".to_string())
);
}
}
104 changes: 3 additions & 101 deletions src/input.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common::InputMode;
use crate::history::BufferHistoryContainer;
use crate::util::events::{CsvlensEvent, CsvlensEvents};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;
use tui_input::backend::crossterm::EventHandler;
use tui_input::Input;

Expand Down Expand Up @@ -51,105 +51,6 @@ enum BufferState {
Inactive,
}

#[derive(Clone, PartialEq, Eq, Hash, Copy)]
pub enum InputMode {
Default,
GotoLine,
Find,
Filter,
FilterColumns,
Option,
Help,
}

struct BufferHistory {
buffers: Vec<String>,
cursor: usize,
}

impl BufferHistory {
fn new_with(buf: &str) -> Self {
BufferHistory {
buffers: vec![buf.to_string()],
cursor: 1,
}
}

fn push(&mut self, buf: &str) {
if buf.is_empty() {
// Don't keep empty entries
return;
}
if let Some(index) = self.buffers.iter().position(|x| x == buf) {
// Don't keep duplicate entries
self.buffers.remove(index);
}
self.buffers.push(buf.to_string());
self.reset_cursor();
}

fn prev(&mut self) -> Option<String> {
if self.cursor == 0 {
return None;
}
self.cursor = self.cursor.saturating_sub(1);
Some(self.buffers[self.cursor].clone())
}

fn next(&mut self) -> Option<String> {
if self.cursor >= self.buffers.len() - 1 {
return None;
}
self.cursor = self.cursor.saturating_add(1);
Some(self.buffers[self.cursor].clone())
}

fn reset_cursor(&mut self) {
self.cursor = self.buffers.len();
}
}

pub struct BufferHistoryContainer {
inner: HashMap<InputMode, BufferHistory>,
}

impl BufferHistoryContainer {
fn new() -> Self {
BufferHistoryContainer {
inner: HashMap::new(),
}
}

fn set(&mut self, input_mode: InputMode, content: &str) {
match self.inner.entry(input_mode) {
Occupied(mut e) => {
e.get_mut().push(content);
}
Vacant(e) => {
e.insert(BufferHistory::new_with(content));
}
}
}

fn prev(&mut self, input_mode: InputMode) -> Option<String> {
self.inner
.get_mut(&input_mode)
.and_then(|history| history.prev())
}

fn next(&mut self, input_mode: InputMode) -> Option<String> {
self.inner
.get_mut(&input_mode)
.and_then(|history| history.next())
}

fn reset_cursors(&mut self) {
for (_, history) in self.inner.iter_mut() {
history.reset_cursor();
}
}
}

pub struct InputHandler {
events: CsvlensEvents,
mode: InputMode,
Expand Down Expand Up @@ -256,6 +157,7 @@ impl InputHandler {
Control::BufferReset
}
KeyCode::Char('g' | 'G') | KeyCode::Enter if self.mode == InputMode::GotoLine => {
self.buffer_history_container.set(self.mode, input.value());
let goto_line = match &self.buffer_state {
BufferState::Active(input) => input.value().parse::<usize>().ok(),
BufferState::Inactive => None,
Expand Down
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod app;
mod common;
mod csv;
mod delimiter;
mod find;
mod help;
mod history;
mod input;
mod ui;
#[allow(dead_code)]
Expand Down
2 changes: 1 addition & 1 deletion src/ui.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::common::InputMode;
use crate::csv::Row;
use crate::find;
use crate::input::InputMode;
use crate::view;
use crate::view::Header;
use crate::wrap;
Expand Down

0 comments on commit c51f94b

Please sign in to comment.