use crate::command_options::{
Arity, DEFAULT_MODE, Occurrence, OptionError, OptionSpec, ParsedOptions, UNREAD, parse_options,
row,
};
use crate::command_options_query::{
WrapperFlags, is_enabled, last_occurrence, positional_tokens, split_wrapper_flags,
};
use std::ffi::OsString;
pub const ADD_ESCAPE_HATCH: &str = "--no-enforce-bulk-add";
pub const ALL: u16 = 1;
pub const IGNORE_REMOVAL: u16 = 2;
pub const UPDATE: u16 = 3;
pub const RESOLVED: u16 = 4;
pub const ADD_TABLE: &[OptionSpec] = &[
row(UNREAD, Some(b'n'), Some("dry-run"), Arity::None, true),
row(UNREAD, Some(b'v'), Some("verbose"), Arity::None, true),
row(UNREAD, Some(b'i'), Some("interactive"), Arity::None, true),
row(UNREAD, Some(b'p'), Some("patch"), Arity::None, true),
row(UNREAD, None, Some("auto-advance"), Arity::None, true),
row(UNREAD, Some(b'U'), Some("unified"), Arity::Required, false),
row(
UNREAD,
None,
Some("inter-hunk-context"),
Arity::Required,
false,
),
row(UNREAD, Some(b'e'), Some("edit"), Arity::None, true),
row(UNREAD, Some(b'f'), Some("force"), Arity::None, true),
row(UPDATE, Some(b'u'), Some("update"), Arity::None, true),
row(UNREAD, None, Some("renormalize"), Arity::None, true),
row(RESOLVED, None, Some("resolved"), Arity::None, true),
row(UNREAD, Some(b'N'), Some("intent-to-add"), Arity::None, true),
row(ALL, Some(b'A'), Some("all"), Arity::None, true),
row(
IGNORE_REMOVAL,
None,
Some("ignore-removal"),
Arity::None,
true,
),
row(UNREAD, None, Some("refresh"), Arity::None, true),
row(UNREAD, None, Some("ignore-errors"), Arity::None, true),
row(UNREAD, None, Some("ignore-missing"), Arity::None, true),
row(UNREAD, None, Some("sparse"), Arity::None, true),
row(UNREAD, None, Some("chmod"), Arity::Required, true),
row(UNREAD, None, Some("warn-embedded-repo"), Arity::None, true),
row(
UNREAD,
None,
Some("pathspec-from-file"),
Arity::Required,
true,
),
row(UNREAD, None, Some("pathspec-file-nul"), Arity::None, true),
];
const BULK_PATHSPECS: &[&[u8]] = &[b".", b"./", b"*", b":/"];
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BulkKind {
AllFlag,
UpdateFlag,
Pathspec,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BulkMatch {
pub kind: BulkKind,
pub token: usize,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AddRegion {
pub bulk_matches: Vec<BulkMatch>,
pub resolved: bool,
pub wrapper: WrapperFlags,
}
fn all_token(parsed: &ParsedOptions) -> Option<usize> {
let mut on: Option<usize> = None;
for occurrence in &parsed.occurrences {
let all_sets: bool = occurrence.id == ALL && !occurrence.negated;
let removal_sets: bool = occurrence.id == IGNORE_REMOVAL && occurrence.negated;
if all_sets || removal_sets {
on = Some(occurrence.token);
} else if occurrence.id == ALL || occurrence.id == IGNORE_REMOVAL {
on = None;
}
}
return on;
}
fn update_token(parsed: &ParsedOptions) -> Option<usize> {
let last: Option<Occurrence> = last_occurrence(parsed, UPDATE);
if let Some(found) = last {
if found.negated {
return None;
}
return Some(found.token);
}
return None;
}
fn match_token(found: &BulkMatch) -> usize {
return found.token;
}
pub fn parse_add_region(
region: &[OsString],
wrapper_flags: &[&[u8]],
) -> Result<AddRegion, OptionError> {
let mut flags: Vec<&[u8]> = Vec::<&[u8]>::with_capacity(wrapper_flags.len() + 1);
flags.push(ADD_ESCAPE_HATCH.as_bytes());
for flag in wrapper_flags {
flags.push(*flag);
}
let parsed: ParsedOptions = parse_options(region, ADD_TABLE, DEFAULT_MODE, flags.as_slice())?;
let mut bulk_matches: Vec<BulkMatch> = Vec::<BulkMatch>::new();
if let Some(token) = all_token(&parsed) {
bulk_matches.push(BulkMatch {
kind: BulkKind::AllFlag,
token,
});
}
if let Some(token) = update_token(&parsed) {
bulk_matches.push(BulkMatch {
kind: BulkKind::UpdateFlag,
token,
});
}
for token in positional_tokens(&parsed, region.len()) {
if BULK_PATHSPECS.contains(®ion[token].as_encoded_bytes()) {
bulk_matches.push(BulkMatch {
kind: BulkKind::Pathspec,
token,
});
}
}
bulk_matches.sort_by_key(match_token);
return Ok(AddRegion {
bulk_matches,
resolved: is_enabled(&parsed, RESOLVED),
wrapper: split_wrapper_flags(parsed.wrapper.as_slice()),
});
}
#[cfg(test)]
#[path = "command_add_tests.rs"]
mod tests;