use super::*;
pub(super) fn filename<B: Buffer>(
state: &mut Ed<'_, B>,
ui: &mut dyn UI,
path: &str,
) -> Result<(), &'static str> {
match parse_path(path) {
None => { ui.print_message(
if state.path.is_empty() { NO_FILE }
else { &state.path }
)?;
}
Some(x) => { state.path = x.to_string();
}
}
Ok(())
}
pub(super) fn read_from_file<B: Buffer>(
state: &mut Ed<'_, B>,
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;
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(&state.path);
let datalen = state.buffer.read_from(path, index, command == 'E')?;
if command != 'r' {
state.path = path.to_string();
}
let index = index.unwrap_or(1);
state.selection = (index, index + datalen - 1);
Ok(())
}
}
pub(super) fn write_to_file<B: Buffer>(
state: &mut Ed<'_, B>,
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(&state.path))
}
else {
(true, &state.path[..])
};
if q && sel.is_some() { return Err(UNSAVED_CHANGES); }
let append = command == 'W';
state.buffer.write_to(sel, path, append)?;
match sel {
None => {
if !append { state.path = path.to_string(); }
},
Some(s) => {
state.selection = (s.0, s.1);
},
}
Ok(q)
}
pub(super) fn scroll<B: Buffer>(
state: &mut Ed<'_, B>,
pflags: &mut PrintingFlags,
selection: Option<Sel<'_>>,
command: char,
clean: &str,
default_scroll_length: usize,
) -> Result<(), &'static str> {
let sel = interpret_selection(selection, state.selection, state.buffer)?;
let index = if command == 'z' {
sel.1
} else {
sel.0
};
verify_index(state.buffer, index)?;
let nr_end = clean.find( | c: char | !c.is_numeric() ).unwrap_or(clean.len());
let nr = if nr_end == 0 {
default_scroll_length
} else {
clean[.. nr_end].parse::<usize>().map_err(|_| INTEGER_PARSE)?
};
let mut flags = parse_flags(&clean[nr_end ..], "pnl")?;
pflags.p = true; pflags.n = flags.remove(&'n').unwrap();
pflags.l = flags.remove(&'l').unwrap();
let new_sel = if command == 'z' {
let start = state.buffer.len().min(index + 1);
let end = state.buffer.len().min(index + nr);
(start, end)
} else {
(index.saturating_sub(1 + nr), index.saturating_sub(1))
};
verify_selection(state.buffer, new_sel)?;
state.selection = new_sel;
Ok(())
}
pub(super) fn input<B: Buffer>(
state: &mut Ed<'_, B>,
ui: &mut dyn UI,
pflags: &mut PrintingFlags,
selection: Option<Sel<'_>>,
command: char,
flags: &str,
) -> Result<(), &'static str> {
let sel = interpret_selection(selection, state.selection, state.buffer)?;
let mut flags = parse_flags(flags, "pnl")?;
pflags.p = flags.remove(&'p').unwrap();
pflags.n = flags.remove(&'n').unwrap();
pflags.l = flags.remove(&'l').unwrap();
match command {
'a' => verify_index(state.buffer, sel.1)?,
'i' => verify_index(state.buffer, sel.0.saturating_sub(1))?,
'A' => verify_line(state.buffer, sel.1)?,
'I' => verify_line(state.buffer, sel.0)?,
_ => { panic!("Unreachable code reached"); }
}
let tmp = ui.get_input(
state.see_state(),
'.',
#[cfg(feature = "initial_input_data")]
None,
)?;
let mut input = tmp.iter().map(|string| &string[..]);
state.selection = if input.len() != 0 {
let index = if command == 'a' || command == 'A' {
sel.1
}
else {
sel.0.saturating_sub(1)
};
let start = index + 1; let end = start + input.len() - 1; state.buffer.insert(&mut input, index)?;
match command {
'A' => {
state.buffer.join((index, index + 1))?;
(start.saturating_sub(1), end.saturating_sub(1))
},
'I' => {
state.buffer.join((end, end + 1))?;
(start,end)
},
'a' | 'i' => {
(start, end)
},
_ => { panic!("Unreachable code reached"); }
}
}
else {
state.selection
};
Ok(())
}
pub(super) fn change<B: Buffer>(
state: &mut Ed<'_, B>,
ui: &mut dyn UI,
pflags: &mut PrintingFlags,
selection: Option<Sel<'_>>,
command: char,
flags: &str,
) -> Result<(), &'static str> {
let sel = interpret_selection(selection, state.selection, state.buffer)?;
let mut flags = parse_flags(flags, "pnl")?;
pflags.p = flags.remove(&'p').unwrap();
pflags.n = flags.remove(&'n').unwrap();
pflags.l = flags.remove(&'l').unwrap();
#[allow(unused_variables)]
let initial_input_data: Option<Vec<String>> = if command == 'C' {
#[cfg(feature = "initial_input_data")]
{
Some(state.buffer.get_selection(sel)?.map(|s| s.1.to_string()).collect())
}
#[cfg(not(feature = "initial_input_data"))]
{
return Err(UNDEFINED_COMMAND);
}
} else {
verify_selection(state.buffer, sel)?;
None
};
let input = ui.get_input(
state.see_state(),
'.',
#[cfg(feature = "initial_input_data")]
initial_input_data,
)?;
let inputlen = input.len();
let mut input = input.iter().map(|string| &string[..]);
state.buffer.change(&mut input, sel)?;
state.selection = if inputlen != 0 {
(sel.0, sel.0 + inputlen - 1)
}
else {
(1.max(sel.0 - 1), sel.0 - 1)
};
Ok(())
}
pub(super) fn transfer<B: Buffer>(
state: &mut Ed<'_, B>,
pflags: &mut PrintingFlags,
selection: Option<Sel<'_>>,
command: char,
tail: &str,
) -> Result<(), &'static str> {
let (ind_end, ind) = parse_index(tail)?;
let index = interpret_index(
ind.unwrap_or(Ind::BufferLen),
state.buffer,
state.selection.1,
)?;
let mut flags = parse_flags(&tail[ind_end..], "pnl")?;
pflags.p = flags.remove(&'p').unwrap();
pflags.n = flags.remove(&'n').unwrap();
pflags.l = flags.remove(&'l').unwrap();
let selection = interpret_selection(selection, state.selection, state.buffer)?;
let move_size = selection.1 - selection.0;
if command == 'm' {
state.buffer.mov(selection, index)?;
} else {
state.buffer.mov_copy(selection,index)?;
};
state.selection = if command == 'm' && selection.1 < index {
(index - move_size, index)
} else {
(index + 1, index + move_size + 1)
};
Ok(())
}
pub(super) fn substitute<B: Buffer>(
state: &mut Ed<'_, B>,
pflags: &mut PrintingFlags,
selection: Option<Sel<'_>>,
tail: &str,
) -> Result<(), &'static str> {
let selection = interpret_selection(selection, state.selection, state.buffer)?;
if tail.is_empty() {
match &state.prev_s {
None => return Err(NO_PRIOR_S),
Some(s) => {
pflags.p = s.p;
pflags.n = s.n;
pflags.l = s.l;
let end = state.buffer.search_replace((&s.pattern, &s.substitute), selection, s.global)?;
state.selection = (selection.0.min(end).max(1), end);
}
}
}
else {
let expressions = parse_expressions(tail)?;
if expressions.len() != 3 { return Err(EXPRESSION_TOO_SHORT); }
let mut flags = parse_flags(&(expressions[2]), "gpnl")?;
let g = flags.remove(&'g').unwrap();
pflags.p = flags.remove(&'p').unwrap();
pflags.n = flags.remove(&'n').unwrap();
pflags.l = flags.remove(&'l').unwrap();
let end = state.buffer.search_replace((&expressions[0], &expressions[1]), selection, g)?;
state.selection = (selection.0.min(end).max(1), end);
state.prev_s = Some(Substitution{
pattern: expressions[0].to_string(),
substitute: expressions[1].to_string(),
global: g,
p: pflags.p,
n: pflags.n,
l: pflags.l,
});
}
Ok(())
}
pub(super) fn global<B: Buffer>(
state: &mut Ed<'_, B>,
ui: &mut dyn UI,
selection: Option<Sel<'_>>,
command: char,
tail: &str,
) -> Result<(), &'static str> {
let selection = interpret_selection(selection, state.selection, state.buffer)?;
verify_selection(state.buffer, selection)?;
let mut expressions = parse_expressions(tail)?;
if expressions.len() < 2 { return Err(EXPRESSION_TOO_SHORT); }
state.buffer.mark_matching(&expressions[0], selection, command == 'v')?;
let mut commands: Vec<String> = expressions.split_off(1).iter().map(|s| s.to_string()).collect();
if commands.last().map(|s| s.trim()) != Some("") {
let mut input = ui.get_input(
state.see_state(),
tail.chars().next().unwrap(),
#[cfg(feature = "initial_input_data")]
None,
)?;
commands.append(&mut input);
}
else {
commands.pop();
}
while let Some(index) = state.buffer.get_marked()? {
let mut dummy = DummyUI{
input: commands.iter().cloned().collect(),
print_ui: Some(ui),
};
state.selection = (index, index);
state.run_macro(&mut dummy)?;
}
Ok(())
}
pub(super) fn global_inv<B: Buffer>(
state: &mut Ed<'_, B>,
ui: &mut dyn UI,
selection: Option<Sel<'_>>,
command: char,
tail: &str,
) -> Result<(), &'static str> {
let selection = interpret_selection(selection, state.selection, state.buffer)?;
verify_selection(state.buffer, selection)?;
let expressions = parse_expressions(tail)?;
if expressions.len() != 2 { return Err(EXPRESSION_TOO_SHORT); }
if !expressions[1].is_empty() && expressions[1] != "\n" { return Err(UNDEFINED_FLAG); }
state.buffer.mark_matching(&expressions[0], selection, command == 'V')?;
while let Some(index) = state.buffer.get_marked()? {
ui.print_selection(state.see_state(), (index, index), state.n, state.l)?;
let input = ui.get_input(
state.see_state(),
tail.chars().next().unwrap(),
#[cfg(feature = "initial_input_data")]
None,
)?;
let mut dummy = DummyUI{
input: input.into(),
print_ui: Some(ui),
};
state.selection = (index, index);
state.run_macro(&mut dummy)?;
}
Ok(())
}