use super::*;
pub(super) fn filename<I: IO>(
state: &mut Ed<'_, I>,
ui: &mut dyn UI,
path: &str,
) -> Result<(), &'static str> {
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(INVALID_FILE),
Path::File(file) => { state.file = file.to_owned(); },
}
}
}
Ok(())
}
pub(super) fn read_from_file<I: IO>(
state: &mut Ed<'_, I>,
ui: &mut dyn UI,
selection: Option<Sel<'_>>,
command: char,
path: &str,
) -> Result<(), &'static str> {
let index =
if command == 'r' {
let i = interpret_selection(selection, state.selection, state.buffer)?.1;
verify_index(state.buffer, i)?;
Ok(Some(i))
}
else if selection.is_none() {
Ok(None)
}
else {
Err(SELECTION_FORBIDDEN)
}
?;
if !state.buffer.saved() && command == 'e' {
Err(UNSAVED_CHANGES)
}
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,
)?;
state.prev_shell_command = substituted.clone();
if changed {ui.print_message( &substituted )?;}
state.io.run_read_command(
&mut ui.lock_ui(),
substituted,
)?
},
Path::File(file) => {
state.io.read_file(file, command == 'E')?
},
};
let data: Vec<&str> = (&unformated_data).split_inclusive('\n').collect();
let datalen = data.len();
match index {
Some(i) => state.buffer.insert(data, i),
None => state.buffer.replace_buffer(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.buffer.len() == datalen && command != 'r' {
state.file = file.to_owned();
state.buffer.set_saved();
}
},
}
Ok(())
}
}
pub(super) fn write_to_file<I: IO>(
state: &mut Ed<'_, I>,
ui: &mut dyn UI,
selection: Option<Sel<'_>>,
command: char,
path: &str,
) -> Result<bool, &'static str> {
let sel = match selection {
Some(s) => {
let inter = interpret_selection(Some(s), state.selection, state.buffer)?;
if inter == (1, state.buffer.len()) {
None
} else {
Some(inter)
}
},
None => None,
};
let (q, path) = if path != "q" {
(false, parse_path(path).unwrap_or(Path::File(&state.file)))
}
else {
(true, (Path::File(&state.file)))
};
if q && sel.is_some() { return Err(UNSAVED_CHANGES); }
let data = state.buffer.get_selection(
sel.unwrap_or((1, state.buffer.len()))
)?
.map(|x| x.1)
;
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.buffer.set_saved();
}
},
Path::Command(cmd) => {
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)
}
pub fn run_command<I: IO>(
state: &mut Ed<'_, I>,
ui: &mut dyn UI,
selection: Option<Sel<'_>>,
ch: char,
command: &str,
) -> Result<(), &'static str> {
let sel = if ch == '!' && selection.is_none() {
None
}
else {
Some(interpret_selection(selection, state.selection, state.buffer)?)
};
let (changed, substituted) = command_substitutions(
command,
&state.file,
&state.prev_shell_command,
)?;
state.prev_shell_command = substituted.clone();
if changed {ui.print_message( &substituted )?;}
match sel {
None => {
state.io.run_command(
&mut ui.lock_ui(),
substituted,
)?;
ui.print_message("!")?;
},
Some(s) => {
let data = state.buffer.get_selection(s)?.map(|x| x.1);
let transformed = state.io.run_transform_command(
&mut ui.lock_ui(),
substituted,
data,
)?;
let lines: Vec<&str> = (&transformed).split_inclusive('\n').collect();
let nr_lines = lines.len();
state.buffer.change(lines, s)?;
state.selection = if nr_lines != 0 {
(s.0, s.0 + nr_lines - 1)
}
else {
(1.max(s.0 - 1), s.0 - 1)
};
ui.print_message(&format!(
"Transformation returned {} bytes through command `{}`",
transformed.len(),
&state.prev_shell_command,
))?;
},
}
Ok(())
}