mirror of
https://git.sr.ht/~nixgoat/vento
synced 2024-11-23 23:33:40 +00:00
Compare commits
4 commits
cba202fd0d
...
e96110748e
Author | SHA1 | Date | |
---|---|---|---|
Lux Aliaga | e96110748e | ||
Lux Aliaga | 46ac7ee8b7 | ||
Lux Aliaga | 600c3e4f3a | ||
Lux Aliaga | 92b2942471 |
834
Cargo.lock
generated
834
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "vento"
|
name = "vento"
|
||||||
version = "1.3.0"
|
version = "1.4.0-alpha"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
|
@ -21,11 +21,14 @@ colored = "2"
|
||||||
fs_extra = "1.3"
|
fs_extra = "1.3"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
size_format = "1.0.2"
|
size_format = "1.0.2"
|
||||||
config = "0.13"
|
config = "0.14"
|
||||||
xz2 = "0.1"
|
xz2 = "0.1"
|
||||||
tar = "0.4"
|
tar = "0.4"
|
||||||
clap = { version = "4.3.23", features = ["derive"] }
|
clap = { version = "4.3.23", features = ["derive"] }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
rusqlite = { version = "0.31.0", features = ["bundled"] }
|
||||||
|
chrono = "0.4"
|
||||||
|
termion = "3.0.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
man = "0.3.0"
|
man = "0.3.0"
|
||||||
|
|
20
build.rs
20
build.rs
|
@ -60,7 +60,25 @@ fn vento() -> Result<Page> {
|
||||||
Flag::new()
|
Flag::new()
|
||||||
.short("-u")
|
.short("-u")
|
||||||
.long("--undo")
|
.long("--undo")
|
||||||
.help("Undoes the last action"),
|
.help("Undoes actions by a certain amount of steps"),
|
||||||
|
)
|
||||||
|
.flag(
|
||||||
|
Flag::new()
|
||||||
|
.short("-r")
|
||||||
|
.long("--redo")
|
||||||
|
.help("Redoes actions by a certain amount of steps"),
|
||||||
|
)
|
||||||
|
.flag(
|
||||||
|
Flag::new()
|
||||||
|
.short("-v")
|
||||||
|
.long("--view")
|
||||||
|
.help("Shows log of actions"),
|
||||||
|
)
|
||||||
|
.flag(
|
||||||
|
Flag::new()
|
||||||
|
.short("-m")
|
||||||
|
.long("--migrate")
|
||||||
|
.help("Migrates history file to database"),
|
||||||
)
|
)
|
||||||
.flag(
|
.flag(
|
||||||
Flag::new()
|
Flag::new()
|
||||||
|
|
|
@ -44,7 +44,7 @@ fn main() -> Result<()> {
|
||||||
let slot = unwrapped_slot.as_str();
|
let slot = unwrapped_slot.as_str();
|
||||||
let out = cli.output.unwrap_or(get_current_dir()?);
|
let out = cli.output.unwrap_or(get_current_dir()?);
|
||||||
|
|
||||||
item::drop(&cli.file, slot, out, true, cli.slot.is_some())?;
|
item::drop(&cli.file, slot, out, true, cli.slot.is_some(), true)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,6 @@ fn main() -> Result<()> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let slot = cli.slot.clone().unwrap_or(String::from("active"));
|
let slot = cli.slot.clone().unwrap_or(String::from("active"));
|
||||||
|
|
||||||
item::take(&cli.file, &slot, true, cli.slot.is_some())?;
|
item::take(&cli.file, &slot, true, cli.slot.is_some(), true)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,21 @@ struct Cli {
|
||||||
#[arg(short = 'c', long)]
|
#[arg(short = 'c', long)]
|
||||||
switch: bool,
|
switch: bool,
|
||||||
|
|
||||||
/// Undo the last action
|
/// Undo actions by a certain amount of steps
|
||||||
|
#[arg(short, long, value_name="STEPS", default_missing_value = "1", num_args = ..=1)]
|
||||||
|
undo: Option<usize>,
|
||||||
|
|
||||||
|
/// Redo actions by a certain amount of steps
|
||||||
|
#[arg(short, long, value_name="STEPS", default_missing_value = "1", num_args = ..=1)]
|
||||||
|
redo: Option<usize>,
|
||||||
|
|
||||||
|
/// View log of actions
|
||||||
|
#[arg(short = 'v', long, value_name="LENGTH", default_missing_value = "2", num_args = ..=1)]
|
||||||
|
view: Option<isize>,
|
||||||
|
|
||||||
|
/// Migrate history file to database
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
undo: bool,
|
migrate: bool,
|
||||||
|
|
||||||
/// Export an inventory
|
/// Export an inventory
|
||||||
#[arg(short, long, value_names = &["SLOT", "ARCHIVE"], num_args = ..=2)]
|
#[arg(short, long, value_names = &["SLOT", "ARCHIVE"], num_args = ..=2)]
|
||||||
|
@ -73,11 +85,17 @@ fn main() -> Result<()> {
|
||||||
let dir = unwrapped_dir.as_str();
|
let dir = unwrapped_dir.as_str();
|
||||||
|
|
||||||
if cli.switch {
|
if cli.switch {
|
||||||
inv::switch(true)?
|
inv::switch(true, true)?
|
||||||
} else if cli.undo {
|
|
||||||
history::undo()?
|
|
||||||
} else if cli.init {
|
} else if cli.init {
|
||||||
inv::init()?
|
inv::init()?
|
||||||
|
} else if cli.undo.is_some() {
|
||||||
|
history::undo(cli.undo.unwrap_or(1))?
|
||||||
|
} else if cli.redo.is_some() {
|
||||||
|
history::redo(cli.redo.unwrap_or(1))?
|
||||||
|
} else if cli.view.is_some() {
|
||||||
|
history::view(cli.view.unwrap_or(2))?
|
||||||
|
} else if cli.migrate {
|
||||||
|
history::migrate()?;
|
||||||
} else if cli.export_inv.is_some() {
|
} else if cli.export_inv.is_some() {
|
||||||
let unwrapped_export_inv = cli.export_inv.unwrap();
|
let unwrapped_export_inv = cli.export_inv.unwrap();
|
||||||
let export_inv_values = match unwrapped_export_inv.len() {
|
let export_inv_values = match unwrapped_export_inv.len() {
|
||||||
|
|
|
@ -21,11 +21,11 @@ use crate::message::{throw_error, ErrorType};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use colored::control::set_override;
|
use colored::control::set_override;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
use rusqlite::Connection;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
pub vento_dir: PathBuf,
|
pub vento_dir: PathBuf,
|
||||||
|
@ -33,11 +33,15 @@ pub struct Settings {
|
||||||
pub inactive_dir: PathBuf,
|
pub inactive_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct HistoryData {
|
pub struct HistoryData {
|
||||||
pub path: PathBuf,
|
pub id: i32,
|
||||||
pub file: String,
|
pub path: Option<PathBuf>,
|
||||||
pub slot: String,
|
pub file: Option<String>,
|
||||||
|
pub slot: Option<String>,
|
||||||
pub action: Action,
|
pub action: Action,
|
||||||
|
pub time: i64,
|
||||||
|
pub current: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DeserializedConfig {
|
pub struct DeserializedConfig {
|
||||||
|
@ -60,6 +64,7 @@ struct History {
|
||||||
display_dir: bool,
|
display_dir: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Take,
|
Take,
|
||||||
Drop,
|
Drop,
|
||||||
|
@ -139,26 +144,48 @@ pub fn parse_config() -> Result<DeserializedConfig> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes an action into the history file
|
/// Writes an action into the history database
|
||||||
pub fn history(data: HistoryData) -> Result<()> {
|
pub fn history(data: HistoryData) -> Result<()> {
|
||||||
let mut last_path = env_config()?.vento_dir;
|
let mut path = env_config()?.vento_dir;
|
||||||
last_path.push("last");
|
path.push("history.db3");
|
||||||
let mut last_file = File::create(last_path)?;
|
let db = Connection::open(path)?;
|
||||||
|
|
||||||
write!(
|
// Create table if it doesn't exist.
|
||||||
&mut last_file,
|
db.execute(
|
||||||
"{}
|
"CREATE TABLE IF NOT EXISTS history (
|
||||||
{}
|
id INTEGER PRIMARY KEY,
|
||||||
{}
|
path TEXT,
|
||||||
{}",
|
file TEXT,
|
||||||
data.path.to_str().unwrap(),
|
slot TEXT,
|
||||||
data.file,
|
action TEXT NOT NULL,
|
||||||
data.slot,
|
time INTEGER NOT NULL,
|
||||||
match data.action {
|
current INTEGER NOT NULL)",
|
||||||
Action::Take => "take",
|
(),
|
||||||
Action::Drop => "drop",
|
)?;
|
||||||
Action::Switch => "switch",
|
|
||||||
}
|
// Remove future actions
|
||||||
|
let mut current = db.prepare("SELECT id FROM history WHERE current = 1")?;
|
||||||
|
let actions = current.query_map([], |row| row.get(0))?;
|
||||||
|
let lastaction: i64 = actions.last().unwrap_or(Ok(0))?;
|
||||||
|
db.execute("DELETE FROM history WHERE id > ?1", [lastaction])?;
|
||||||
|
|
||||||
|
// Unset current actions
|
||||||
|
db.execute("UPDATE history SET current = 0 WHERE current = 1", ())?;
|
||||||
|
|
||||||
|
// Insert action into table
|
||||||
|
db.execute(
|
||||||
|
"INSERT INTO history (path, file, slot, action, time, current) VALUES (?1, ?2, ?3, ?4, ?5, 1)",
|
||||||
|
(
|
||||||
|
data.path.unwrap_or_default().to_str(),
|
||||||
|
data.file,
|
||||||
|
data.slot,
|
||||||
|
match data.action {
|
||||||
|
Action::Take => "take",
|
||||||
|
Action::Drop => "drop",
|
||||||
|
Action::Switch => "switch",
|
||||||
|
},
|
||||||
|
SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or(Duration::new(0, 0)).as_secs(),
|
||||||
|
),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
638
src/history.rs
638
src/history.rs
|
@ -18,98 +18,174 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{env_config, parse_config},
|
common::{self, env_config, parse_config, Action, HistoryData},
|
||||||
inv, item,
|
inv, item,
|
||||||
message::{append_emoji, throw_error, EmojiType, ErrorType},
|
message::{append_emoji, throw_error, EmojiType, ErrorType},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use chrono::prelude::*;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use std::fs;
|
use rusqlite::Connection;
|
||||||
use std::path::{Path, PathBuf};
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
/// Undoes the last action made by Vento using the history file located on the Vento directory
|
/// Undoes actions made by Vento using the history database located on the Vento directory
|
||||||
pub fn undo() -> Result<()> {
|
pub fn undo(steps: usize) -> Result<()> {
|
||||||
let lastpath: PathBuf = [env_config()?.vento_dir, Path::new("last").to_path_buf()]
|
let path: PathBuf = [
|
||||||
.iter()
|
env_config()?.vento_dir,
|
||||||
.collect();
|
Path::new("history.db3").to_path_buf(),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
let db = Connection::open(path)?;
|
||||||
|
|
||||||
let lastfile = fs::read_to_string(lastpath)?;
|
// Determine if step amount is greater than the position of the action
|
||||||
|
let mut current = db.prepare("SELECT id FROM history WHERE current = 1")?;
|
||||||
|
let actions = current.query_map([], |row| row.get(0))?;
|
||||||
|
let last_action: usize = actions.last().unwrap_or(Ok(0))?;
|
||||||
|
|
||||||
let mut contents = vec![];
|
if last_action <= steps {
|
||||||
|
throw_error(ErrorType::InvalidStepsLength)?;
|
||||||
for line in lastfile.lines() {
|
|
||||||
contents.push(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if contents.len() != 4 {
|
let final_dest = last_action - steps;
|
||||||
throw_error(ErrorType::InvalidHistoryLength)?;
|
|
||||||
|
// Calculates how many actions need to be undone
|
||||||
|
let mut undo_queue_transaction = db.prepare(
|
||||||
|
"SELECT id, path, file, slot, action FROM history WHERE id > ?2 AND id <= ?1 ORDER BY id DESC",
|
||||||
|
)?;
|
||||||
|
let undo_queue = undo_queue_transaction.query_map([last_action, final_dest], |row| {
|
||||||
|
Ok(HistoryData {
|
||||||
|
id: row.get(0)?,
|
||||||
|
path: Some(PathBuf::from(row.get::<_, String>(1)?)),
|
||||||
|
file: row.get(2)?,
|
||||||
|
slot: row.get(3)?,
|
||||||
|
action: match row.get::<_, String>(4)?.as_str() {
|
||||||
|
"take" => Action::Take,
|
||||||
|
"drop" => Action::Drop,
|
||||||
|
"switch" => Action::Switch,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
time: 0,
|
||||||
|
current: 0,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Undoes actions for each step
|
||||||
|
for raw_step in undo_queue {
|
||||||
|
let step = raw_step?;
|
||||||
|
|
||||||
|
match step.action {
|
||||||
|
Action::Take => {
|
||||||
|
item::drop(
|
||||||
|
&step.file.unwrap(),
|
||||||
|
&step.slot.unwrap(),
|
||||||
|
step.path.unwrap(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Action::Drop => {
|
||||||
|
let path: String = [
|
||||||
|
String::from(step.path.unwrap().to_str().unwrap()),
|
||||||
|
step.file.unwrap(),
|
||||||
|
]
|
||||||
|
.join("/");
|
||||||
|
item::take(&path, step.slot.unwrap().as_str(), false, false, false)?;
|
||||||
|
}
|
||||||
|
Action::Switch => inv::switch(false, false)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
db.execute("UPDATE history SET current = 0 WHERE current = 1", ())?;
|
||||||
|
db.execute(
|
||||||
|
"UPDATE history SET current = 1 WHERE id = ?1",
|
||||||
|
[step.id - 1],
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match contents[3] {
|
// Prepares to display details of the final position
|
||||||
"take" => {
|
let mut final_transaction = db.prepare("SELECT * FROM history WHERE current = 1")?;
|
||||||
let destpath = Path::new(contents[0]).to_path_buf();
|
let final_action_iter = final_transaction.query_map([], |row| {
|
||||||
item::drop(
|
Ok(HistoryData {
|
||||||
&String::from(contents[1]),
|
id: row.get(0)?,
|
||||||
contents[2],
|
path: Some(PathBuf::from(row.get::<_, String>(1)?)),
|
||||||
destpath,
|
file: row.get(2)?,
|
||||||
false,
|
slot: row.get(3)?,
|
||||||
false,
|
action: match row.get::<_, String>(4)?.as_str() {
|
||||||
)?;
|
"take" => Action::Take,
|
||||||
}
|
"drop" => Action::Drop,
|
||||||
"drop" => {
|
"switch" => Action::Switch,
|
||||||
let path = vec![contents[0], contents[1]].join("/");
|
_ => unreachable!(),
|
||||||
item::take(&path, contents[2], false, false)?;
|
},
|
||||||
}
|
time: row.get(5)?,
|
||||||
"switch" => {
|
current: row.get::<_, i32>(5)?,
|
||||||
inv::switch(false)?;
|
})
|
||||||
}
|
})?;
|
||||||
_ => throw_error(ErrorType::IllegalAction)?,
|
|
||||||
}
|
let final_action = final_action_iter.last().unwrap()?;
|
||||||
|
|
||||||
|
// Formats the current action's timestamp to readable, local time
|
||||||
|
let timestamp = final_action.time;
|
||||||
|
let naive = NaiveDateTime::from_timestamp_opt(timestamp, 0);
|
||||||
|
let datetime = TimeZone::from_utc_datetime(&Local, &naive.unwrap());
|
||||||
|
let newdate = datetime.format("%Y-%m-%d, %H:%M:%S");
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"{}{}{}{}",
|
"{}{}{}{}{}{}",
|
||||||
append_emoji(EmojiType::Success)?,
|
append_emoji(EmojiType::Success)?,
|
||||||
match contents[3] {
|
"Rolled back to ".green(),
|
||||||
"take" => "Take",
|
match final_action.action {
|
||||||
"drop" => "Drop",
|
Action::Take => "Take",
|
||||||
"switch" => "Switch",
|
Action::Drop => "Drop",
|
||||||
_ => "Unknown",
|
Action::Switch => "Switch",
|
||||||
}
|
}
|
||||||
.bold(),
|
.bold(),
|
||||||
" action undone".green(),
|
" action, on ".green(),
|
||||||
match contents[3] {
|
newdate,
|
||||||
"take" => format!(
|
match final_action.action {
|
||||||
|
Action::Take => format!(
|
||||||
"{}{}{}{}{}{}{}",
|
"{}{}{}{}{}{}{}",
|
||||||
" (".green(),
|
" (".green(),
|
||||||
contents[1].bold(),
|
final_action.file.unwrap().bold(),
|
||||||
", ".green(),
|
", ".green(),
|
||||||
match parse_config()?.history_display_dir {
|
match parse_config()?.history_display_dir {
|
||||||
true => format!("{} {} ", "from".green(), contents[0],),
|
true => format!(
|
||||||
|
"{} {} ",
|
||||||
|
"from".green(),
|
||||||
|
final_action.path.unwrap().to_str().unwrap(),
|
||||||
|
),
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
},
|
},
|
||||||
"to ".green(),
|
"to ".green(),
|
||||||
match contents[2] {
|
match final_action.slot.clone().unwrap().as_str() {
|
||||||
"active" => contents[2].green(),
|
"active" => final_action.slot.unwrap().green(),
|
||||||
"inactive" => contents[2].blue(),
|
"inactive" => final_action.slot.unwrap().blue(),
|
||||||
_ => contents[2].red(),
|
_ => final_action.slot.unwrap().red(),
|
||||||
}
|
}
|
||||||
.bold(),
|
.bold(),
|
||||||
" slot)".green(),
|
" slot)".green(),
|
||||||
),
|
),
|
||||||
"drop" => format!(
|
Action::Drop => format!(
|
||||||
"{}{}{}{}{}{}{}",
|
"{}{}{}{}{}{}{}",
|
||||||
" (".green(),
|
" (".green(),
|
||||||
contents[1].bold(),
|
final_action.file.unwrap().bold(),
|
||||||
", from ".green(),
|
", from ".green(),
|
||||||
match contents[2] {
|
match final_action.slot.clone().unwrap().as_str() {
|
||||||
"active" => contents[2].green(),
|
"active" => final_action.slot.unwrap().green(),
|
||||||
"inactive" => contents[2].blue(),
|
"inactive" => final_action.slot.unwrap().blue(),
|
||||||
_ => contents[2].red(),
|
_ => final_action.slot.unwrap().red(),
|
||||||
}
|
}
|
||||||
.bold(),
|
.bold(),
|
||||||
" slot".green(),
|
" slot".green(),
|
||||||
match parse_config()?.history_display_dir {
|
match parse_config()?.history_display_dir {
|
||||||
true => format!(" {} {}", "to".green(), contents[0],),
|
true => format!(
|
||||||
|
" {} {}",
|
||||||
|
"to".green(),
|
||||||
|
final_action.path.unwrap().to_str().unwrap(),
|
||||||
|
),
|
||||||
false => String::new(),
|
false => String::new(),
|
||||||
},
|
},
|
||||||
")".green(),
|
")".green(),
|
||||||
|
@ -120,3 +196,451 @@ pub fn undo() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Redoes actions made by Vento using the history database located on the Vento directory
|
||||||
|
pub fn redo(steps: usize) -> Result<()> {
|
||||||
|
let path: PathBuf = [
|
||||||
|
env_config()?.vento_dir,
|
||||||
|
Path::new("history.db3").to_path_buf(),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
let db = Connection::open(path)?;
|
||||||
|
|
||||||
|
// Determine if step amount is greater than the position of the action
|
||||||
|
let mut current = db.prepare("SELECT id FROM history WHERE current = 1")?;
|
||||||
|
let actions = current.query_map([], |row| row.get(0))?;
|
||||||
|
let last_action: usize = actions.last().unwrap_or(Ok(0))?;
|
||||||
|
|
||||||
|
// Determine table size
|
||||||
|
let mut size_transaction = db.prepare("SELECT id FROM history")?;
|
||||||
|
let size_actions = size_transaction.query_map([], |row| row.get(0))?;
|
||||||
|
let size: usize = size_actions.last().unwrap_or(Ok(0))?;
|
||||||
|
|
||||||
|
if size - last_action < steps {
|
||||||
|
throw_error(ErrorType::InvalidStepsLength)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let final_dest = last_action + steps;
|
||||||
|
|
||||||
|
// Calculates how many actions need to be redone
|
||||||
|
let mut redo_queue_transaction = db.prepare(
|
||||||
|
"SELECT id, path, file, slot, action FROM history WHERE id > ?1 AND id <= ?2 ORDER BY id ASC",
|
||||||
|
)?;
|
||||||
|
let redo_queue = redo_queue_transaction.query_map([last_action, final_dest], |row| {
|
||||||
|
Ok(HistoryData {
|
||||||
|
id: row.get(0)?,
|
||||||
|
path: Some(PathBuf::from(row.get::<_, String>(1)?)),
|
||||||
|
file: row.get(2)?,
|
||||||
|
slot: row.get(3)?,
|
||||||
|
action: match row.get::<_, String>(4)?.as_str() {
|
||||||
|
"take" => Action::Take,
|
||||||
|
"drop" => Action::Drop,
|
||||||
|
"switch" => Action::Switch,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
time: 0,
|
||||||
|
current: 0,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Redoes actions for each step
|
||||||
|
for raw_step in redo_queue {
|
||||||
|
let step = raw_step?;
|
||||||
|
|
||||||
|
match step.action {
|
||||||
|
Action::Take => {
|
||||||
|
let path: String = [
|
||||||
|
String::from(step.path.unwrap().to_str().unwrap()),
|
||||||
|
step.file.unwrap(),
|
||||||
|
]
|
||||||
|
.join("/");
|
||||||
|
item::take(&path, step.slot.unwrap().as_str(), false, false, false)?;
|
||||||
|
}
|
||||||
|
Action::Drop => {
|
||||||
|
item::drop(
|
||||||
|
&step.file.unwrap(),
|
||||||
|
&step.slot.unwrap(),
|
||||||
|
step.path.unwrap(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Action::Switch => inv::switch(false, false)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
db.execute("UPDATE history SET current = 0 WHERE current = 1", ())?;
|
||||||
|
db.execute("UPDATE history SET current = 1 WHERE id = ?1", [step.id])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepares to display details of the final position
|
||||||
|
let mut final_transaction = db.prepare("SELECT * FROM history WHERE current = 1")?;
|
||||||
|
let final_action_iter = final_transaction.query_map([], |row| {
|
||||||
|
Ok(HistoryData {
|
||||||
|
id: row.get(0)?,
|
||||||
|
path: Some(PathBuf::from(row.get::<_, String>(1)?)),
|
||||||
|
file: row.get(2)?,
|
||||||
|
slot: row.get(3)?,
|
||||||
|
action: match row.get::<_, String>(4)?.as_str() {
|
||||||
|
"take" => Action::Take,
|
||||||
|
"drop" => Action::Drop,
|
||||||
|
"switch" => Action::Switch,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
time: row.get(5)?,
|
||||||
|
current: row.get::<_, i32>(5)?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let final_action = final_action_iter.last().unwrap()?;
|
||||||
|
|
||||||
|
// Formats the current action's timestamp to readable, local time
|
||||||
|
let timestamp = final_action.time;
|
||||||
|
let naive = NaiveDateTime::from_timestamp_opt(timestamp, 0);
|
||||||
|
let datetime = TimeZone::from_utc_datetime(&Local, &naive.unwrap());
|
||||||
|
let newdate = datetime.format("%Y-%m-%d, %H:%M:%S");
|
||||||
|
|
||||||
|
// Prints transaction result
|
||||||
|
println!(
|
||||||
|
"{}{}{}{}{}{}",
|
||||||
|
append_emoji(EmojiType::Success)?,
|
||||||
|
"Returned to ".green(),
|
||||||
|
match final_action.action {
|
||||||
|
Action::Take => "Take",
|
||||||
|
Action::Drop => "Drop",
|
||||||
|
Action::Switch => "Switch",
|
||||||
|
}
|
||||||
|
.bold(),
|
||||||
|
" action, on ".green(),
|
||||||
|
newdate,
|
||||||
|
match final_action.action {
|
||||||
|
Action::Take => format!(
|
||||||
|
"{}{}{}{}{}{}{}",
|
||||||
|
" (".green(),
|
||||||
|
final_action.file.unwrap().bold(),
|
||||||
|
", ".green(),
|
||||||
|
match parse_config()?.history_display_dir {
|
||||||
|
true => format!(
|
||||||
|
"{} {} ",
|
||||||
|
"from".green(),
|
||||||
|
final_action.path.unwrap().to_str().unwrap(),
|
||||||
|
),
|
||||||
|
_ => String::new(),
|
||||||
|
},
|
||||||
|
"to ".green(),
|
||||||
|
match final_action.slot.clone().unwrap().as_str() {
|
||||||
|
"active" => final_action.slot.unwrap().green(),
|
||||||
|
"inactive" => final_action.slot.unwrap().blue(),
|
||||||
|
_ => final_action.slot.unwrap().red(),
|
||||||
|
}
|
||||||
|
.bold(),
|
||||||
|
" slot)".green(),
|
||||||
|
),
|
||||||
|
Action::Drop => format!(
|
||||||
|
"{}{}{}{}{}{}{}",
|
||||||
|
" (".green(),
|
||||||
|
final_action.file.unwrap().bold(),
|
||||||
|
", from ".green(),
|
||||||
|
match final_action.slot.clone().unwrap().as_str() {
|
||||||
|
"active" => final_action.slot.unwrap().green(),
|
||||||
|
"inactive" => final_action.slot.unwrap().blue(),
|
||||||
|
_ => final_action.slot.unwrap().red(),
|
||||||
|
}
|
||||||
|
.bold(),
|
||||||
|
" slot".green(),
|
||||||
|
match parse_config()?.history_display_dir {
|
||||||
|
true => format!(
|
||||||
|
" {} {}",
|
||||||
|
"to".green(),
|
||||||
|
final_action.path.unwrap().to_str().unwrap(),
|
||||||
|
),
|
||||||
|
false => String::new(),
|
||||||
|
},
|
||||||
|
")".green(),
|
||||||
|
),
|
||||||
|
_ => String::from(""),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Displays n actions before and after the current action
|
||||||
|
pub fn view(length: isize) -> Result<()> {
|
||||||
|
let path: PathBuf = [
|
||||||
|
env_config()?.vento_dir,
|
||||||
|
Path::new("history.db3").to_path_buf(),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
let db = Connection::open(path)?;
|
||||||
|
|
||||||
|
// Determine table size
|
||||||
|
let mut size_transaction = db.prepare("SELECT id FROM history")?;
|
||||||
|
let size_actions = size_transaction.query_map([], |row| row.get(0))?;
|
||||||
|
let size: isize = size_actions.last().unwrap_or(Ok(0))?;
|
||||||
|
|
||||||
|
let (x, _) = termion::terminal_size().unwrap();
|
||||||
|
|
||||||
|
// If there's no history, don't print the table
|
||||||
|
if size == 0 {
|
||||||
|
println!(
|
||||||
|
"{}{}",
|
||||||
|
append_emoji(EmojiType::Success)?,
|
||||||
|
"No data to show".green()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find last action
|
||||||
|
let mut current = db.prepare("SELECT id FROM history WHERE current = 1")?;
|
||||||
|
let actions = current.query_map([], |row| row.get(0))?;
|
||||||
|
let last_action: isize = actions.last().unwrap_or(Ok(0))?;
|
||||||
|
|
||||||
|
let mut forward: isize = last_action + length;
|
||||||
|
let mut backward: isize = last_action - length;
|
||||||
|
let total_range: isize = length * 2;
|
||||||
|
|
||||||
|
// Changes ranges in case they exceed the table margins
|
||||||
|
if forward >= size {
|
||||||
|
forward = size;
|
||||||
|
backward = size - total_range;
|
||||||
|
} else if backward < 1 {
|
||||||
|
backward = 1;
|
||||||
|
forward = total_range + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from table
|
||||||
|
let mut history_transaction =
|
||||||
|
db.prepare("SELECT * FROM history WHERE id >= ?1 AND id <= ?2")?;
|
||||||
|
let history = history_transaction.query_map([backward, forward], |row| {
|
||||||
|
Ok(HistoryData {
|
||||||
|
id: row.get(0)?,
|
||||||
|
path: Some(PathBuf::from(row.get::<_, String>(1)?)),
|
||||||
|
file: row.get(2)?,
|
||||||
|
slot: row.get(3)?,
|
||||||
|
action: match row.get::<_, String>(4)?.as_str() {
|
||||||
|
"take" => Action::Take,
|
||||||
|
"drop" => Action::Drop,
|
||||||
|
"switch" => Action::Switch,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
time: row.get(5)?,
|
||||||
|
current: row.get(6)?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Terminal needs to be at least 83 columns wide
|
||||||
|
if x < 83 {
|
||||||
|
throw_error(ErrorType::SmallTerminal)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut space_left: usize = (x - 83).into();
|
||||||
|
|
||||||
|
// Append separators to ID
|
||||||
|
let mut id_separators = String::new();
|
||||||
|
if size.to_string().len() > 2 {
|
||||||
|
for _ in 0..size.to_string().len() - 2 {
|
||||||
|
id_separators.insert(id_separators.len(), '-')
|
||||||
|
}
|
||||||
|
space_left = space_left - size.to_string().len() + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append separators to path column
|
||||||
|
let mut path_separators = String::new();
|
||||||
|
let mut file_separators = String::new();
|
||||||
|
|
||||||
|
// Calculate spaces left to add padding to the path and file separators
|
||||||
|
space_left /= 3;
|
||||||
|
for _ in 0..space_left * 2 {
|
||||||
|
path_separators.insert(path_separators.len(), '-')
|
||||||
|
}
|
||||||
|
for _ in 0..space_left {
|
||||||
|
file_separators.insert(file_separators.len(), '-')
|
||||||
|
}
|
||||||
|
|
||||||
|
let separator = format!(
|
||||||
|
"+----{}+---------------------+--------+------------------{}+----------{}+----------+---+",
|
||||||
|
id_separators, path_separators, file_separators
|
||||||
|
);
|
||||||
|
|
||||||
|
// Render the first column names
|
||||||
|
println!("{}", separator);
|
||||||
|
print!("| ");
|
||||||
|
if size.to_string().len() > 2 {
|
||||||
|
for _ in 0..size.to_string().len() - 2 {
|
||||||
|
print!(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print!("ID | Date | Action | Path ");
|
||||||
|
for _ in 0..space_left * 2 {
|
||||||
|
print!(" ")
|
||||||
|
}
|
||||||
|
print!("| File ");
|
||||||
|
for _ in 0..space_left {
|
||||||
|
print!(" ")
|
||||||
|
}
|
||||||
|
println!("| Slot | C |\n{}", separator);
|
||||||
|
|
||||||
|
// Print the rows
|
||||||
|
for raw_step in history {
|
||||||
|
let step = raw_step?;
|
||||||
|
|
||||||
|
// Format timestamp on row
|
||||||
|
let timestamp = step.time;
|
||||||
|
let naive = NaiveDateTime::from_timestamp_opt(timestamp, 0);
|
||||||
|
let datetime = TimeZone::from_utc_datetime(&Local, &naive.unwrap());
|
||||||
|
let fdate = datetime.format("%Y-%m-%d %H:%M:%S");
|
||||||
|
|
||||||
|
// Add spacing for ID column
|
||||||
|
let mut id_pad = String::new();
|
||||||
|
let id = step.id.to_string().len();
|
||||||
|
|
||||||
|
if size.to_string().len() >= 2 {
|
||||||
|
let id_pad_len = size.to_string().len();
|
||||||
|
for x in 0..id_pad_len - id {
|
||||||
|
id_pad.insert(x, ' ');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
id_pad.insert(0, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add spacing to fit inside the file column
|
||||||
|
let file_len = match &step.file {
|
||||||
|
Some(x) => x.len(),
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
let mut file_pad = String::new();
|
||||||
|
let mut file = step.file.unwrap_or(String::from(""));
|
||||||
|
let file_column_len;
|
||||||
|
if file_len > space_left + 8 {
|
||||||
|
file_column_len = 0;
|
||||||
|
let mut reversed: String = file.chars().rev().collect();
|
||||||
|
for _ in 0..file_len - space_left - 5 {
|
||||||
|
reversed.pop();
|
||||||
|
}
|
||||||
|
file = reversed.chars().rev().collect();
|
||||||
|
for x in 0..3 {
|
||||||
|
file.insert(x, '.');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file_column_len = space_left + 8 - file_len
|
||||||
|
}
|
||||||
|
|
||||||
|
for x in 0..file_column_len {
|
||||||
|
file_pad.insert(x, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add spacing to fit inside the path column
|
||||||
|
let mut path_pad = String::new();
|
||||||
|
let mut path = step
|
||||||
|
.path
|
||||||
|
.unwrap_or(PathBuf::new())
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
let path_len = path.len();
|
||||||
|
let path_column_len;
|
||||||
|
if path_len > space_left * 2 + 16 {
|
||||||
|
path_column_len = 0;
|
||||||
|
let mut reversed: String = path.chars().rev().collect();
|
||||||
|
for _ in 0..path_len - space_left * 2 - 13 {
|
||||||
|
reversed.pop();
|
||||||
|
}
|
||||||
|
path = reversed.chars().rev().collect();
|
||||||
|
for x in 0..3 {
|
||||||
|
path.insert(x, '.');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path_column_len = space_left * 2 + 16 - path_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..path_column_len {
|
||||||
|
path_pad.insert(path_pad.len(), ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add spacing on slot column
|
||||||
|
let mut slot = step.slot.unwrap_or(String::from(""));
|
||||||
|
if slot == "active" {
|
||||||
|
slot = String::from("active ");
|
||||||
|
} else if slot == "inactive" {
|
||||||
|
slot = String::from("inactive");
|
||||||
|
} else {
|
||||||
|
slot = String::from(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"| {}{} | {} | {} | {}{} | {}{} | {} | {} |",
|
||||||
|
id_pad,
|
||||||
|
step.id,
|
||||||
|
fdate,
|
||||||
|
match step.action {
|
||||||
|
Action::Take => "Take ",
|
||||||
|
Action::Drop => "Drop ",
|
||||||
|
Action::Switch => "Switch",
|
||||||
|
},
|
||||||
|
path,
|
||||||
|
path_pad,
|
||||||
|
file,
|
||||||
|
file_pad,
|
||||||
|
slot,
|
||||||
|
match step.current {
|
||||||
|
0 => " ",
|
||||||
|
1 => "*",
|
||||||
|
_ => " ",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("{}", separator);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Migrate old "last" file into the history database
|
||||||
|
pub fn migrate() -> Result<()> {
|
||||||
|
// Get last file from previous location
|
||||||
|
let last_path: PathBuf = [env_config()?.vento_dir, Path::new("last").to_path_buf()]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if !last_path.is_file() {
|
||||||
|
throw_error(ErrorType::NoFileOrDir)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_file = fs::read_to_string(&last_path)?;
|
||||||
|
|
||||||
|
let mut contents = vec![];
|
||||||
|
|
||||||
|
for line in last_file.lines() {
|
||||||
|
contents.push(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if contents.len() != 4 {
|
||||||
|
throw_error(ErrorType::InvalidHistoryLength)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write contents of file into history database
|
||||||
|
common::history(HistoryData {
|
||||||
|
id: 0,
|
||||||
|
path: Some(Path::new(contents[0]).to_path_buf()),
|
||||||
|
file: Some(String::from(contents[1])),
|
||||||
|
slot: Some(String::from(contents[2])),
|
||||||
|
action: match contents[3] {
|
||||||
|
"take" => Action::Take,
|
||||||
|
"drop" => Action::Drop,
|
||||||
|
"switch" => Action::Switch,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
time: 0,
|
||||||
|
current: 1,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
fs::remove_file(last_path)?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{}{}",
|
||||||
|
append_emoji(EmojiType::Success)?,
|
||||||
|
"Migrated history file to database".green()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
19
src/inv.rs
19
src/inv.rs
|
@ -178,7 +178,7 @@ pub fn list(slot: &str, dir: &str, display_slot: bool) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Switches inevntory slots between each other, making the currently active inventory inactive and viceversa
|
/// Switches inevntory slots between each other, making the currently active inventory inactive and viceversa
|
||||||
pub fn switch(message: bool) -> Result<()> {
|
pub fn switch(message: bool, save_history: bool) -> Result<()> {
|
||||||
let ventodir = &common::env_config()?.vento_dir;
|
let ventodir = &common::env_config()?.vento_dir;
|
||||||
let active = &common::env_config()?.active_dir;
|
let active = &common::env_config()?.active_dir;
|
||||||
let inactive = &common::env_config()?.inactive_dir;
|
let inactive = &common::env_config()?.inactive_dir;
|
||||||
|
@ -192,12 +192,17 @@ pub fn switch(message: bool) -> Result<()> {
|
||||||
fs::rename(inactive, active).context(rename_error)?;
|
fs::rename(inactive, active).context(rename_error)?;
|
||||||
fs::rename(&temp, inactive).context(rename_error)?;
|
fs::rename(&temp, inactive).context(rename_error)?;
|
||||||
|
|
||||||
common::history(common::HistoryData {
|
if save_history {
|
||||||
path: PathBuf::new(),
|
common::history(common::HistoryData {
|
||||||
file: String::new(),
|
id: 0,
|
||||||
slot: String::new(),
|
path: None,
|
||||||
action: common::Action::Switch,
|
file: None,
|
||||||
})?;
|
slot: None,
|
||||||
|
action: common::Action::Switch,
|
||||||
|
current: 1,
|
||||||
|
time: 0,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
if message {
|
if message {
|
||||||
println!(
|
println!(
|
||||||
|
|
43
src/item.rs
43
src/item.rs
|
@ -28,7 +28,13 @@ use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
/// Takes a file or directory and stores it in an inventory slot
|
/// Takes a file or directory and stores it in an inventory slot
|
||||||
pub fn take(file: &String, slot: &str, message: bool, display_slot: bool) -> Result<()> {
|
pub fn take(
|
||||||
|
file: &String,
|
||||||
|
slot: &str,
|
||||||
|
message: bool,
|
||||||
|
display_slot: bool,
|
||||||
|
save_history: bool,
|
||||||
|
) -> Result<()> {
|
||||||
let ventodir = &env_config()?.vento_dir;
|
let ventodir = &env_config()?.vento_dir;
|
||||||
|
|
||||||
if !ventodir.is_dir() {
|
if !ventodir.is_dir() {
|
||||||
|
@ -78,12 +84,17 @@ pub fn take(file: &String, slot: &str, message: bool, display_slot: bool) -> Res
|
||||||
throw_error(ErrorType::NoFileOrDir)?;
|
throw_error(ErrorType::NoFileOrDir)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
history(HistoryData {
|
if save_history {
|
||||||
path: sourcelocation.clone(),
|
history(HistoryData {
|
||||||
file: String::from(filename),
|
id: 0,
|
||||||
slot: String::from(slot),
|
path: Some(sourcelocation.clone()),
|
||||||
action: Action::Take,
|
file: Some(String::from(filename)),
|
||||||
})?;
|
slot: Some(String::from(slot)),
|
||||||
|
action: Action::Take,
|
||||||
|
current: 1,
|
||||||
|
time: 0,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
if message {
|
if message {
|
||||||
println!(
|
println!(
|
||||||
|
@ -125,6 +136,7 @@ pub fn drop(
|
||||||
dest: PathBuf,
|
dest: PathBuf,
|
||||||
message: bool,
|
message: bool,
|
||||||
display_slot: bool,
|
display_slot: bool,
|
||||||
|
save_history: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Drops a file or directory
|
// Drops a file or directory
|
||||||
let ventodir = &env_config()?.vento_dir;
|
let ventodir = &env_config()?.vento_dir;
|
||||||
|
@ -180,12 +192,17 @@ pub fn drop(
|
||||||
|
|
||||||
destpath.pop();
|
destpath.pop();
|
||||||
|
|
||||||
history(HistoryData {
|
if save_history {
|
||||||
path: destpath.clone(),
|
history(HistoryData {
|
||||||
file: String::from(file),
|
id: 0,
|
||||||
slot: String::from(slot),
|
path: Some(destpath.clone()),
|
||||||
action: Action::Drop,
|
file: Some(String::from(file)),
|
||||||
})?;
|
slot: Some(String::from(slot)),
|
||||||
|
action: Action::Drop,
|
||||||
|
current: 1,
|
||||||
|
time: 0,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
if message {
|
if message {
|
||||||
println!(
|
println!(
|
||||||
|
|
|
@ -28,6 +28,8 @@ pub enum ErrorType {
|
||||||
NoCurrentDirectory,
|
NoCurrentDirectory,
|
||||||
NoHomeDirectory,
|
NoHomeDirectory,
|
||||||
InvalidHistoryLength,
|
InvalidHistoryLength,
|
||||||
|
InvalidStepsLength,
|
||||||
|
SmallTerminal,
|
||||||
IllegalAction,
|
IllegalAction,
|
||||||
NotInitialized,
|
NotInitialized,
|
||||||
NoAccessParent,
|
NoAccessParent,
|
||||||
|
@ -68,7 +70,9 @@ pub fn throw_error(error: ErrorType) -> Result<()> {
|
||||||
ErrorType::SpecifySlot => "You need to specify a slot",
|
ErrorType::SpecifySlot => "You need to specify a slot",
|
||||||
ErrorType::NoCurrentDirectory => "Vento was unable to detect your current directory. Have you configured your environment correctly?",
|
ErrorType::NoCurrentDirectory => "Vento was unable to detect your current directory. Have you configured your environment correctly?",
|
||||||
ErrorType::NoHomeDirectory => "Vento was unable to detect your home directory. Have you configured your environment correctly?",
|
ErrorType::NoHomeDirectory => "Vento was unable to detect your home directory. Have you configured your environment correctly?",
|
||||||
ErrorType::InvalidHistoryLength => "Invalid history length",
|
ErrorType::InvalidHistoryLength => "Invalid history length",
|
||||||
|
ErrorType::InvalidStepsLength => "Invalid steps length",
|
||||||
|
ErrorType::SmallTerminal => "Your terminal needs to be at least 83 columns wide",
|
||||||
ErrorType::IllegalAction => "Illegal action",
|
ErrorType::IllegalAction => "Illegal action",
|
||||||
ErrorType::NotInitialized => "Vento not initialized. Run \"vento -i\" to initialize Vento",
|
ErrorType::NotInitialized => "Vento not initialized. Run \"vento -i\" to initialize Vento",
|
||||||
ErrorType::NoAccessParent => "Cannot access parent",
|
ErrorType::NoAccessParent => "Cannot access parent",
|
||||||
|
|
Loading…
Reference in a new issue