use crate::buffer::BufferSnapshot;
pub struct Xlc {
pub open: bool,
pub input: String,
pub output: Vec<String>,
pub history: Vec<String>,
pub history_index: usize,
pub scroll_offset: usize,
}
impl Default for Xlc {
fn default() -> Self {
Self {
open: false,
input: String::new(),
output: vec!["xei Line Command — :help for commands".to_string()],
history: Vec::new(),
history_index: 0,
scroll_offset: 0,
}
}
}
impl Xlc {
pub fn new() -> Self {
Self::default()
}
pub fn open_panel(&mut self, prompt: Option<&str>) {
self.open = true;
self.input.clear();
self.history_index = self.history.len();
self.scroll_offset = 0;
if let Some(p) = prompt {
self.input = p.to_string();
}
}
pub fn close(&mut self) {
self.open = false;
self.input.clear();
}
pub fn push_char(&mut self, c: char) {
self.input.push(c);
}
pub fn pop_char(&mut self) {
self.input.pop();
}
pub fn history_up(&mut self) {
if self.history.is_empty() {
return;
}
if self.history_index > 0 {
self.history_index -= 1;
self.input = self.history[self.history_index].clone();
}
}
pub fn history_down(&mut self) {
if self.history_index < self.history.len() {
self.history_index += 1;
if self.history_index < self.history.len() {
self.input = self.history[self.history_index].clone();
} else {
self.input.clear();
}
}
}
pub fn execute(&mut self) -> XlcCmd {
let cmd = self.input.trim().to_string();
if !cmd.is_empty() {
self.history.push(cmd.clone());
}
self.history_index = self.history.len();
self.output.push(format!("> {}", cmd));
let result = parse_command(&cmd);
self.input.clear();
result
}
pub fn add_output(&mut self, msg: &str) {
self.output.push(msg.to_string());
}
pub fn scroll_up(&mut self, amount: usize) {
self.scroll_offset = self
.scroll_offset
.saturating_add(amount)
.min(self.output.len().saturating_sub(1));
}
pub fn scroll_down(&mut self, amount: usize) {
self.scroll_offset = self.scroll_offset.saturating_sub(amount);
}
#[allow(dead_code)]
pub fn scroll_reset(&mut self) {
self.scroll_offset = 0;
}
pub fn scroll_to_top(&mut self) {
self.scroll_offset = self.output.len().saturating_sub(1);
}
pub fn scroll_to_bottom(&mut self) {
self.scroll_offset = 0;
}
}
#[derive(Debug)]
pub enum XlcCmd {
None,
Save,
SaveAs(String),
Quit,
ForceQuit,
Open(String),
Move(String),
Rename(String),
DeleteFile,
Pwd,
Ls,
Help,
Search(String),
Theme(String),
}
fn parse_command(input: &str) -> XlcCmd {
let parts: Vec<&str> = input.splitn(2, ' ').collect();
let cmd = parts[0];
let arg = parts.get(1).map(|s| s.trim()).unwrap_or("");
match cmd {
"w" | "save" => {
if arg.is_empty() {
XlcCmd::Save
} else {
XlcCmd::SaveAs(arg.to_string())
}
}
"q" | "quit" => XlcCmd::Quit,
"q!" | "quit!" => XlcCmd::ForceQuit,
"wq" | "x" => XlcCmd::Save,
"e" | "open" if !arg.is_empty() => XlcCmd::Open(arg.to_string()),
"mv" | "move" if !arg.is_empty() => XlcCmd::Move(arg.to_string()),
"rename" if !arg.is_empty() => XlcCmd::Rename(arg.to_string()),
"rm" => XlcCmd::DeleteFile,
"pwd" => XlcCmd::Pwd,
"ls" => XlcCmd::Ls,
"help" | "h" | "?" => XlcCmd::Help,
"find" | "/" if !arg.is_empty() => XlcCmd::Search(arg.to_string()),
"theme" => XlcCmd::Theme(arg.to_string()),
_ => XlcCmd::None,
}
}
pub struct UndoStack {
snapshots: Vec<BufferSnapshot>,
index: usize,
}
impl Default for UndoStack {
fn default() -> Self {
Self {
snapshots: Vec::new(),
index: 0,
}
}
}
impl UndoStack {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, snapshot: BufferSnapshot) {
self.snapshots.truncate(self.index);
self.snapshots.push(snapshot);
self.index += 1;
}
pub fn undo(&mut self) -> Option<&BufferSnapshot> {
if self.index > 1 {
self.index -= 1;
Some(&self.snapshots[self.index - 1])
} else if self.index == 1 {
self.index -= 1;
Some(&self.snapshots[self.index])
} else {
None
}
}
}