use super::main::{Zle, ZleChar, ZleString};
impl Zle {
pub fn insert_str(&mut self, s: &str) {
for c in s.chars() {
self.zleline.insert(self.zlecs, c);
self.zlecs += 1;
self.zlell += 1;
}
self.resetneeded = true;
}
pub fn insert_chars(&mut self, chars: &[ZleChar]) {
for &c in chars {
self.zleline.insert(self.zlecs, c);
self.zlecs += 1;
self.zlell += 1;
}
self.resetneeded = true;
}
pub fn delete_chars(&mut self, n: usize) {
let n = n.min(self.zlell - self.zlecs);
for _ in 0..n {
if self.zlecs < self.zlell {
self.zleline.remove(self.zlecs);
self.zlell -= 1;
}
}
self.resetneeded = true;
}
pub fn backspace_chars(&mut self, n: usize) {
let n = n.min(self.zlecs);
for _ in 0..n {
if self.zlecs > 0 {
self.zlecs -= 1;
self.zleline.remove(self.zlecs);
self.zlell -= 1;
}
}
self.resetneeded = true;
}
pub fn get_line(&self) -> String {
self.zleline.iter().collect()
}
pub fn set_line(&mut self, s: &str) {
self.zleline = s.chars().collect();
self.zlell = self.zleline.len();
self.zlecs = self.zlecs.min(self.zlell);
self.resetneeded = true;
}
pub fn clear_line(&mut self) {
self.zleline.clear();
self.zlell = 0;
self.zlecs = 0;
self.mark = 0;
self.resetneeded = true;
}
pub fn get_region(&self) -> &[ZleChar] {
let (start, end) = if self.zlecs < self.mark {
(self.zlecs, self.mark)
} else {
(self.mark, self.zlecs)
};
&self.zleline[start..end]
}
pub fn cut_to_buffer(&mut self, buf: usize, append: bool) {
if buf < self.vibuf.len() {
let (start, end) = if self.zlecs < self.mark {
(self.zlecs, self.mark)
} else {
(self.mark, self.zlecs)
};
let text: ZleString = self.zleline[start..end].to_vec();
if append {
self.vibuf[buf].extend(text);
} else {
self.vibuf[buf] = text;
}
}
}
pub fn paste_from_buffer(&mut self, buf: usize, after: bool) {
if buf < self.vibuf.len() {
let text = self.vibuf[buf].clone();
if !text.is_empty() {
if after && self.zlecs < self.zlell {
self.zlecs += 1;
}
self.insert_chars(&text);
}
}
}
}
pub fn metafy(s: &str) -> String {
s.to_string()
}
pub fn unmetafy(s: &str) -> String {
s.to_string()
}
pub fn strwidth(s: &str) -> usize {
s.chars().count()
}
pub fn is_printable(c: char) -> bool {
!c.is_control() && c != '\x7f'
}
pub fn escape_for_display(c: char) -> String {
if c.is_control() {
if c as u32 <= 26 {
format!("^{}", (c as u8 + b'@') as char)
} else {
format!("\\x{:02x}", c as u32)
}
} else if c == '\x7f' {
"^?".to_string()
} else {
c.to_string()
}
}
#[derive(Debug, Clone)]
pub struct UndoEntry {
pub start: usize,
pub end: usize,
pub text: ZleString,
pub cursor: usize,
pub group_start: bool,
}
#[derive(Debug, Default)]
pub struct UndoState {
pub history: Vec<UndoEntry>,
pub current: usize,
pub limit: usize,
pub recording: bool,
pub merge_inserts: bool,
}
impl UndoState {
pub fn new() -> Self {
UndoState {
recording: true,
merge_inserts: true,
..Default::default()
}
}
pub fn init(&mut self) {
self.history.clear();
self.current = 0;
self.limit = 0;
self.recording = true;
}
pub fn free(&mut self) {
self.history.clear();
self.current = 0;
}
pub fn make_entry(&mut self, start: usize, end: usize, text: ZleString, cursor: usize) {
if !self.recording {
return;
}
self.history.truncate(self.current);
let entry = UndoEntry {
start,
end,
text,
cursor,
group_start: false,
};
self.history.push(entry);
self.current = self.history.len();
}
pub fn split(&mut self) {
if let Some(entry) = self.history.last_mut() {
entry.group_start = true;
}
}
pub fn merge(&mut self) {
if self.history.len() >= 2 {
let last = self.history.len() - 1;
let prev = last - 1;
if self.history[prev].end == self.history[last].start
&& self.history[prev].text.is_empty()
&& self.history[last].text.is_empty()
{
self.history[prev].end = self.history[last].end;
self.history.pop();
self.current = self.history.len();
}
}
}
pub fn get_current(&self) -> Option<&UndoEntry> {
if self.current > 0 {
self.history.get(self.current - 1)
} else {
None
}
}
pub fn set_limit(&mut self) {
self.limit = self.current;
}
pub fn get_limit(&self) -> usize {
self.limit
}
}
impl Zle {
fn apply_change(&mut self, entry: &UndoEntry, reverse: bool) {
if reverse {
let removed: ZleString = self.zleline.drain(entry.start..entry.end).collect();
for (i, &c) in entry.text.iter().enumerate() {
self.zleline.insert(entry.start + i, c);
}
self.zlell = self.zleline.len();
self.zlecs = entry.cursor;
let _ = removed;
} else {
let end = entry.start + entry.text.len();
self.zleline.drain(entry.start..end.min(self.zleline.len()));
for (i, &c) in entry.text.iter().enumerate() {
self.zleline.insert(entry.start + i, c);
}
self.zlell = self.zleline.len();
self.zlecs = entry.cursor;
}
self.resetneeded = true;
}
pub fn find_bol(&self, pos: usize) -> usize {
let mut p = pos;
while p > 0 && self.zleline.get(p - 1) != Some(&'\n') {
p -= 1;
}
p
}
pub fn find_eol(&self, pos: usize) -> usize {
let mut p = pos;
while p < self.zlell && self.zleline.get(p) != Some(&'\n') {
p += 1;
}
p
}
pub fn find_line(&self, pos: usize) -> usize {
self.zleline[..pos].iter().filter(|&&c| c == '\n').count()
}
pub fn size_line(&mut self, needed: usize) {
if self.zleline.capacity() < needed {
self.zleline.reserve(needed - self.zleline.len());
}
}
pub fn space_in_line(&mut self, pos: usize, count: usize) {
for _ in 0..count {
self.zleline.insert(pos, ' ');
}
self.zlell += count;
if self.zlecs >= pos {
self.zlecs += count;
}
}
pub fn shift_chars(&mut self, from: usize, count: i32) {
if count > 0 {
for _ in 0..count {
self.zleline.insert(from, ' ');
}
self.zlell += count as usize;
} else if count < 0 {
let to_remove = (-count) as usize;
for _ in 0..to_remove.min(self.zlell - from) {
self.zleline.remove(from);
}
self.zlell = self.zleline.len();
}
}
pub fn fore_del(&mut self, count: usize, flags: CutFlags) {
let count = count.min(self.zlell - self.zlecs);
if count == 0 {
return;
}
if flags.contains(CutFlags::KILL) {
let text: ZleString = self.zleline[self.zlecs..self.zlecs + count].to_vec();
self.killring.push_front(text);
if self.killring.len() > self.killringmax {
self.killring.pop_back();
}
}
for _ in 0..count {
self.zleline.remove(self.zlecs);
}
self.zlell -= count;
self.resetneeded = true;
}
pub fn back_del(&mut self, count: usize, flags: CutFlags) {
let count = count.min(self.zlecs);
if count == 0 {
return;
}
if flags.contains(CutFlags::KILL) {
let text: ZleString = self.zleline[self.zlecs - count..self.zlecs].to_vec();
self.killring.push_front(text);
if self.killring.len() > self.killringmax {
self.killring.pop_back();
}
}
self.zlecs -= count;
for _ in 0..count {
self.zleline.remove(self.zlecs);
}
self.zlell -= count;
self.resetneeded = true;
}
pub fn fore_kill(&mut self, count: usize, append: bool) {
let count = count.min(self.zlell - self.zlecs);
if count == 0 {
return;
}
let text: ZleString = self.zleline[self.zlecs..self.zlecs + count].to_vec();
if append {
if let Some(front) = self.killring.front_mut() {
front.extend(text);
} else {
self.killring.push_front(text);
}
} else {
self.killring.push_front(text);
}
if self.killring.len() > self.killringmax {
self.killring.pop_back();
}
for _ in 0..count {
self.zleline.remove(self.zlecs);
}
self.zlell -= count;
self.resetneeded = true;
}
pub fn back_kill(&mut self, count: usize, append: bool) {
let count = count.min(self.zlecs);
if count == 0 {
return;
}
let text: ZleString = self.zleline[self.zlecs - count..self.zlecs].to_vec();
if append {
if let Some(front) = self.killring.front_mut() {
let mut new_text = text;
new_text.extend(front.iter());
*front = new_text;
} else {
self.killring.push_front(text);
}
} else {
self.killring.push_front(text);
}
if self.killring.len() > self.killringmax {
self.killring.pop_back();
}
self.zlecs -= count;
for _ in 0..count {
self.zleline.remove(self.zlecs);
}
self.zlell -= count;
self.resetneeded = true;
}
pub fn cut_text(&mut self, start: usize, end: usize, dir: CutDirection) {
if start >= end || end > self.zlell {
return;
}
let text: ZleString = self.zleline[start..end].to_vec();
match dir {
CutDirection::Front => {
self.killring.push_front(text);
}
CutDirection::Back => {
if let Some(front) = self.killring.front_mut() {
front.extend(text);
} else {
self.killring.push_front(text);
}
}
}
if self.killring.len() > self.killringmax {
self.killring.pop_back();
}
}
pub fn set_last_line(&mut self) {
}
pub fn show_msg(&self, msg: &str) {
eprintln!("{}", msg);
}
pub fn handle_feep(&self) {
print!("\x07"); }
pub fn add_to_line(&mut self, pos: usize, text: &str) {
for (i, c) in text.chars().enumerate() {
self.zleline.insert(pos + i, c);
}
self.zlell += text.chars().count();
if self.zlecs >= pos {
self.zlecs += text.chars().count();
}
self.resetneeded = true;
}
pub fn line_as_string(&self) -> String {
self.zleline.iter().collect()
}
pub fn string_as_line(&mut self, s: &str) {
self.zleline = s.chars().collect();
self.zlell = self.zleline.len();
if self.zlecs > self.zlell {
self.zlecs = self.zlell;
}
self.resetneeded = true;
}
pub fn get_zle_line(&self) -> &[ZleChar] {
&self.zleline
}
pub fn get_zle_query(&self) -> Option<String> {
None
}
pub fn handle_suffix(&mut self) {
}
}
#[derive(Debug, Clone)]
pub struct SavedPositions {
pub zlecs: usize,
pub zlell: usize,
pub mark: usize,
}
impl Zle {
pub fn save_positions(&self) -> SavedPositions {
SavedPositions {
zlecs: self.zlecs,
zlell: self.zlell,
mark: self.mark,
}
}
pub fn restore_positions(&mut self, saved: &SavedPositions) {
self.zlecs = saved.zlecs.min(self.zlell);
self.mark = saved.mark.min(self.zlell);
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, Default)]
pub struct CutFlags: u32 {
const KILL = 1 << 0; const COPY = 1 << 1; const APPEND = 1 << 2; }
}
#[derive(Debug, Clone, Copy)]
pub enum CutDirection {
Front,
Back,
}
pub fn print_bind(seq: &[u8]) -> String {
let mut result = String::new();
for &b in seq {
match b {
0x1b => result.push_str("^["),
0..=31 => {
result.push('^');
result.push((b + 64) as char);
}
127 => result.push_str("^?"),
128..=159 => {
result.push_str("^[^");
result.push((b - 64) as char);
}
_ => result.push(b as char),
}
}
result
}
pub fn zle_call_hook(_name: &str, _args: &[&str]) -> i32 {
0
}