Commit 533f66c0 authored by Martin Sehnoutka's avatar Martin Sehnoutka Committed by Sehny

Create new module named history and use code from Ion.

parent 3f18f6fc
target
Cargo.lock
liner.iml
history
......@@ -38,7 +38,7 @@ pub fn get_buffer_words(buf: &Buffer) -> Vec<(usize, usize)> {
}
pub struct Context {
pub history: Vec<Buffer>,
pub history: History,//Vec<Buffer>,
pub completer: Option<Box<Completer>>,
pub word_fn: Box<Fn(&Buffer) -> Vec<(usize, usize)>>,
}
......@@ -46,7 +46,7 @@ pub struct Context {
impl Context {
pub fn new() -> Self {
Context {
history: vec![],
history: History::new(),
completer: None,
word_fn: Box::new(get_buffer_words),
}
......@@ -80,7 +80,7 @@ impl Context {
}
pub fn revert_all_history(&mut self) {
for buf in &mut self.history {
for buf in &mut self.history.history {
buf.revert();
}
}
......
use super::*;
use std::collections::VecDeque;
use std::fs::{File, OpenOptions};
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::ops::Index;
use std::ops::IndexMut;
/// Structure encapsulating command history
pub struct History {
/// TODO: this should eventually be private
pub history: VecDeque<Buffer>,
//pub previous_status: i32,
enabled: bool,
file_name: String,
max_size: usize,
}
impl History {
/// Create new History structure.
pub fn new() -> History {
History {
history: VecDeque::with_capacity(1000),
enabled: false,
file_name: "".to_string(),
max_size: 1000,
}
}
/// Number of items in history.
pub fn len(&self) -> usize {
self.history.len()
}
/// Add a command to the history buffer and remove the oldest commands when the max history
/// size has been met.
pub fn push(&mut self, new_item: Buffer) {
if self.enabled == true {
self.write_to_disk(&new_item);
}
self.history.truncate(self.max_size-1); // Make room for the new item
self.history.push_front(new_item)
}
/// Set history file name. At the same time enable history.
pub fn set_file_name(&mut self, name: String) {
self.file_name = name;
self.enabled = true;
}
/// Set maximum number of items in history.
pub fn set_max_size(&mut self, size: usize) {
self.max_size = size;
}
/// If writing to the disk is enabled, this function will be used for logging history to the
/// designated history file. If the history file does not exist, it will be created.
fn write_to_disk(&self, new_item: &Buffer) {
match OpenOptions::new().read(true).write(true).create(true).open(&self.file_name) {
Ok(mut file) => {
// Determine the number of commands stored and the file length.
let (file_length, commands_stored) = {
let mut commands_stored = 0;
let mut file_length = 0;
let file = File::open(&self.file_name).unwrap();
for byte in file.bytes() {
if byte.unwrap_or(b' ') == b'\n' { commands_stored += 1; }
file_length += 1;
}
(file_length, commands_stored)
};
// If the max history file size has been reached, truncate the file so that only
// N amount of commands are listed. To truncate the file, the seek point will be
// discovered by counting the number of bytes until N newlines have been found and
// then the file will be seeked to that point, copying all data after and rewriting
// the file with the first N lines removed.
if commands_stored >= self.max_size {
let seek_point = {
let commands_to_delete = commands_stored - self.max_size + 1;
let mut matched = 0;
let mut bytes = 0;
let file = File::open(&self.file_name).unwrap();
for byte in file.bytes() {
if byte.unwrap_or(b' ') == b'\n' { matched += 1; }
bytes += 1;
if matched == commands_to_delete { break }
}
bytes as u64
};
if let Err(message) = file.seek(SeekFrom::Start(seek_point)) {
println!("ion: unable to seek in history file: {}", message);
}
let mut buffer: Vec<u8> = Vec::with_capacity(file_length - seek_point as usize);
if let Err(message) = file.read_to_end(&mut buffer) {
println!("ion: unable to buffer history file: {}", message);
}
if let Err(message) = file.set_len(0) {
println!("ion: unable to truncate history file: {}", message);
}
if let Err(message) = io::copy(&mut buffer.as_slice(), &mut file) {
println!("ion: unable to write to history file: {}", message);
}
}
// Seek to end for appending
if let Err(message) = file.seek(SeekFrom::End(0)) {
println!("ion: unable to seek in history file: {}", message);
}
// Write the command to the history file.
if let Err(message) = file.write_all(String::from(new_item.clone()).as_bytes()) {
println!("ion: unable to write to history file: {}", message);
}
if let Err(message) = file.write(b"\n") {
println!("ion: unable to write to history file: {}", message);
}
}
Err(message) => println!("ion: error opening file: {}", message)
}
}
}
impl Index<usize> for History {
type Output = Buffer;
fn index(&self, index: usize) -> &Buffer {
&self.history[index]
}
}
impl IndexMut<usize> for History {
fn index_mut(&mut self, index: usize) -> &mut Buffer {
&mut self.history[index]
}
}
\ No newline at end of file
#![feature(deque_extras)]
extern crate termion;
extern crate unicode_width;
......@@ -16,6 +18,9 @@ pub use context::*;
mod buffer;
pub use buffer::*;
mod history;
pub use history::*;
mod util;
#[cfg(test)]
......
......@@ -2,13 +2,30 @@ extern crate liner;
extern crate termion;
use std::mem::replace;
use std::env::current_dir;
use std::env::{args, current_dir};
use liner::{Context, CursorPosition, Event, EventKind, FilenameCompleter};
fn main() {
let mut con = Context::new();
println!("Printing args...");
for argument in args() {
println!("{}", argument);
}
let file_name;
match args().nth(1) {
Some(str) => file_name = str,
None => {
println!("You have to provide file name");
return
}
}
println!("History file: {}", file_name);
con.history.set_file_name(file_name);
loop {
let res = con.read_line("[prompt]$ ",
&mut |Event { editor, kind }| {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment