use super::*;
pub fn filename(
state: &mut Ed<'_>,
ui: &mut dyn UI,
path: &str,
) -> Result<()> {
match parse_path(path) {
None => { ui.print_message(
if state.file.is_empty() { NO_FILE }
else { &state.file }
)?;
}
Some(x) => { match x {
Path::Command(_) => return Err(EdError::CommandEscapeForbidden(path.into())),
Path::File(file) => { state.file = file.to_owned(); },
}
}
}
Ok(())
}
fn insert<'a>(
buffer: &mut Buffer,
data: impl Iterator<Item = &'a str>,
index: usize,
) -> Result<usize> {
let mut tail = buffer.split_off(index);
let start = buffer.len();
for line in data {
buffer.push(
Line::new(format!("{}\n", line)).map_err(InternalError::InvalidLineText)?
);
}
let end = buffer.len();
buffer.append(&mut tail);
Ok(end - start)
}
fn replace_buffer<'a>(
buffer: &mut Buffer,
data: impl Iterator<Item = &'a str>,
) -> Result<usize> {
buffer.clear();
for line in data {
buffer.push(
Line::new(format!("{}\n", line)).map_err(InternalError::InvalidLineText)?
);
}
Ok(buffer.len())
}
pub fn read_from_file(
state: &mut Ed<'_>,
ui: &mut dyn UI,
full_command: &str,
selection: Option<Sel<'_>>,
command: char,
path: &str,
) -> Result<()> {
let index =
if command == 'r' {
let i = interpret_index_from_selection(&state, selection, state.selection, true)?;
state.history.current().verify_index(i)?;
Ok(Some(i))
}
else if selection.is_none() {
Ok(None)
}
else {
Err(EdError::SelectionForbidden)
}
?;
if !state.history.saved() && command == 'e' {
Err(EdError::UnsavedChanges)
}
else {
let path = parse_path(path).unwrap_or(Path::File(&state.file));
let unformated_data = match path {
Path::Command(cmd) => {
let (changed, substituted) = command_substitutions(
cmd,
&state.file,
&state.prev_shell_command,
)?;
if changed {
ui.print_message( &substituted )?;
}
let data = state.io.run_read_command(
&mut ui.lock_ui(),
substituted.clone(),
)?;
state.prev_shell_command = substituted;
data
},
Path::File(file) => {
state.io.read_file(file, command == 'E')?
},
};
let data = unformated_data.lines();
let datalen = match index {
Some(i) => insert(state.history.current_mut(full_command.into()), data, i),
None => replace_buffer(state.history.current_mut(full_command.into()), data),
}?;
let index = index.unwrap_or(0) + 1;
state.selection = (index, index + datalen - 1);
match path {
Path::Command(_cmd) => {
ui.print_message(&format!(
"Read {} bytes from command `{}`",
unformated_data.len(),
&state.prev_shell_command,
))?;
},
Path::File(file) => {
ui.print_message(&format!(
"Read {} bytes from path `{}`",
unformated_data.len(),
file,
))?;
if state.history.current().len() == datalen && command != 'r' {
state.file = file.to_owned();
state.history.set_saved();
}
},
}
Ok(())
}
}
pub fn write_to_file(
state: &mut Ed<'_>,
ui: &mut dyn UI,
selection: Option<Sel<'_>>,
command: char,
in_path: &str,
) -> Result<bool> {
let sel = match selection {
Some(s) => {
let inter = interpret_selection(&state, Some(s), state.selection)?;
if inter == (1, state.history.current().len()) {
None
} else {
Some(inter)
}
},
None => None,
};
let (q, path) = if in_path != "q" {
(false, parse_path(in_path).unwrap_or(Path::File(&state.file)))
}
else {
(true, (Path::File(&state.file)))
};
if q && sel.is_some() { return Err(EdError::UnsavedChanges); }
let data = state.history.current().get_lines(
sel.unwrap_or((1, state.history.current().len()))
)?
;
match path {
Path::File(file) => {
let append = command == 'W';
let written = state.io.write_file(
file,
append,
data,
)?;
ui.print_message(&format!(
"Wrote {} bytes to path `{}`",
written,
file,
))?;
if sel.is_none() && command != 'W' {
state.file = file.to_string();
state.history.set_saved();
}
},
Path::Command(cmd) => {
if command == 'W' {
return Err(EdError::CommandEscapeForbidden(in_path.to_owned()));
}
let (changed, substituted) = command_substitutions(
cmd,
&state.file,
&state.prev_shell_command,
)?;
state.prev_shell_command = substituted.clone();
if changed {ui.print_message( &substituted )?;}
let written = state.io.run_write_command(
&mut ui.lock_ui(),
substituted,
data,
)?;
ui.print_message(&format!(
"Wrote {} bytes to command `{}`",
written,
&state.prev_shell_command,
))?;
},
}
match sel {
None => (),
Some(s) => {
state.selection = (s.0, s.1);
},
}
Ok(q)
}