use super::*;
impl Buffer {
pub fn inline_insert<S: Into<String>>(&mut self,
mut data: Vec<S>,
index: usize,
) -> Result<()> {
verify_line(self, index)?;
let buffer = self.history.current_mut()?;
let mut tail = buffer.split_off(index);
let indexed_line = buffer.split_off(index - 1);
let last_data_line = data.pop().map(|s| s.into());
for line in data.drain(..) {
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: Rc::new(line.into())}
);
}
let mut joined_text = last_data_line.unwrap_or(String::new());
joined_text.pop(); joined_text.push_str(&indexed_line[0].text[..]);
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: Rc::new(joined_text)}
);
self.clipboard = indexed_line;
buffer.append(&mut tail);
Ok(())
}
pub fn inline_append<S: Into<String>>(&mut self,
mut data: Vec<S>,
index: usize,
) -> Result<()> {
verify_line(self, index)?;
let buffer = self.history.current_mut()?;
let mut tail = buffer.split_off(index);
let indexed_line = buffer.split_off(index - 1);
let mut data_iter = data.drain(..);
let mut joined_text = String::from(&indexed_line[0].text[..]);
if let Some(txt) = data_iter.next() {
joined_text.pop(); joined_text.push_str(txt.into().as_str());
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: Rc::new(joined_text)}
);
}
for line in data_iter {
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: Rc::new(line.into())}
);
}
self.clipboard = indexed_line;
buffer.append(&mut tail);
Ok(())
}
pub fn insert<S: Into<String>>(&mut self,
mut data: Vec<S>,
index: usize,
) -> Result<()> {
verify_index(self, index)?;
let buffer = self.history.current_mut()?;
let mut tail = buffer.split_off(index);
for line in data.drain(..) {
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: Rc::new(line.into())}
);
}
buffer.append(&mut tail);
Ok(())
}
pub fn cut(&mut self,
selection: (usize, usize),
) -> Result<()> {
verify_selection(self, selection)?;
let buffer = self.history.current_mut()?;
let mut tail = buffer.split_off(selection.1);
self.clipboard = buffer.split_off(selection.0.saturating_sub(1));
buffer.append(&mut tail);
Ok(())
}
pub fn change<S: Into<String>>(&mut self,
mut data: Vec<S>,
selection: (usize, usize),
) -> Result<()> {
verify_selection(self, selection)?;
let buffer = self.history.current_mut()?;
let mut tail = buffer.split_off(selection.1);
self.clipboard = buffer.split_off(selection.0.saturating_sub(1));
for line in data.drain(..) {
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: Rc::new(line.into())}
);
}
buffer.append(&mut tail);
Ok(())
}
pub fn replace_buffer<S: Into<String>>(&mut self,
mut data: Vec<S>,
) -> Result<()> {
let buffer = self.history.current_mut()?;
buffer.clear();
for line in data.drain(..) {
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: Rc::new(line.into())}
);
}
Ok(())
}
pub fn mov(&mut self,
selection: (usize, usize),
index: usize,
) -> Result<()> {
verify_selection(self, selection)?;
verify_index(self, index)?;
let buffer = self.history.current_mut()?;
if index < selection.0 {
let mut tail = buffer.split_off(selection.1);
let mut data = buffer.split_off(selection.0.saturating_sub(1));
let mut middle = buffer.split_off(index);
buffer.append(&mut data);
buffer.append(&mut middle);
buffer.append(&mut tail);
Ok(())
}
else if index >= selection.1 {
let mut tail = buffer.split_off(index);
let mut middle = buffer.split_off(selection.1);
let mut data = buffer.split_off(selection.0.saturating_sub(1));
buffer.append(&mut middle);
buffer.append(&mut data);
buffer.append(&mut tail);
Ok(())
}
else {
Err(EdError::NoOp).into() }
}
pub fn mov_copy(&mut self,
selection: (usize, usize),
index: usize,
) -> Result<()> {
verify_selection(self, selection)?;
verify_index(self, index)?;
let buffer = self.history.current_mut()?;
let mut data = Vec::new();
for line in &buffer[selection.0.saturating_sub(1) .. selection.1] {
data.push(line.clone());
}
let mut tail = buffer.split_off(index);
buffer.append(&mut data);
buffer.append(&mut tail);
Ok(())
}
pub fn join(&mut self,
selection: (usize, usize),
) -> Result<()> {
verify_selection(self, selection)?;
let buffer = self.history.current_mut()?;
let mut tail = buffer.split_off(selection.1);
let data = buffer.split_off(selection.0.saturating_sub(1));
buffer.push(data[0].clone());
buffer.append(&mut tail);
let mut text = String::from(
&buffer[selection.0.saturating_sub(1)].text[..]
);
for line in &data[1..] {
text.pop(); text.push_str(&line.text[..]);
}
buffer[selection.0.saturating_sub(1)].text = Rc::new(text);
self.clipboard = data;
Ok(())
}
pub fn reflow(&mut self,
selection: (usize, usize),
width: usize,
) -> Result<usize> {
verify_selection(self, selection)?;
let buffer = self.history.current_mut()?;
let mut tail = buffer.split_off(selection.1);
let data = buffer.split_off(selection.0.saturating_sub(1));
let mut joined = String::new();
for line in &data {
for ch in line.text.chars() {
joined.push(match ch {
'\n' => ' ',
c => c,
})
}
}
self.clipboard = data;
joined.pop();
let mut w = 0; let mut latest_space = None;
for i in 0 .. joined.len() {
if !joined.is_char_boundary(i) { continue; }
w += 1;
if joined[i..].starts_with(' ') {
latest_space = Some(i);
}
if w > width {
if let Some(s) = latest_space {
joined.replace_range(s..=s, "\n");
w = i - s;
latest_space = None;
}
}
}
for line in joined.lines() {
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: format!("{}\n", line).into()}
);
}
let end = buffer.len();
buffer.append(&mut tail);
Ok(end)
}
pub fn copy(&mut self,
selection: (usize, usize),
) -> Result<()> {
verify_selection(self, selection)?;
self.clipboard = Vec::new();
let buffer = self.history.current();
for line in &buffer[selection.0.saturating_sub(1) .. selection.1] {
self.clipboard.push(line.clone());
}
Ok(())
}
pub fn paste(&mut self,
index: usize,
) -> Result<usize> {
verify_index(self, index)?;
let buffer = self.history.current_mut()?;
let mut tmp = buffer.split_off(index);
for line in &self.clipboard {
buffer.push(line.clone());
}
buffer.append(&mut tmp);
Ok(self.clipboard.len())
}
pub fn search_replace(&mut self,
pattern: (&str, &str),
selection: (usize, usize),
global: bool,
) -> Result<usize> {
use regex::RegexBuilder;
verify_selection(self, selection)?;
let regex = RegexBuilder::new(pattern.0)
.multi_line(true)
.build()
.map_err(|e|EdError::regex_error(e, pattern.0))
?;
let buffer_view = self.history.current();
let mut joined = String::new();
for line in &buffer_view[selection.0.saturating_sub(1) .. selection.1] {
joined.push_str(&line.text);
}
if !regex.is_match(&joined) {
Err(EdError::RegexNoMatch(pattern.0.to_owned()))?
}
let buffer = self.history.current_mut()?;
let mut tail = buffer.split_off(selection.1);
let before = buffer
.split_off(selection.0.saturating_sub(1))
;
self.clipboard = before;
let replace = substitute::substitute(pattern.1);
let after = if global {
regex.replace_all(&joined, replace).to_string()
}
else {
regex.replace(&joined, replace).to_string()
};
for line in after.lines() {
buffer.push(
Line{tag: '\0'.into(), matched: false.into(), text: format!("{}\n", line).into()}
);
}
let end = buffer.len();
buffer.append(&mut tail);
Ok(end)
}
}