use crate::command_options::{
Arity, DEFAULT_MODE, OptionError, OptionSpec, ParsedOptions, UNREAD, WrapperOccurrence,
parse_options, row,
};
use crate::command_options_query::is_enabled;
use crate::global_arguments::VALUE_OPTIONS;
use std::ffi::OsString;
pub const SHORT: u16 = 1;
pub const PORCELAIN: u16 = 2;
pub const LONG: u16 = 3;
pub const NULL: u16 = 4;
pub const STATUS_TABLE: &[OptionSpec] = &[
row(UNREAD, Some(b'v'), Some("verbose"), Arity::None, true),
row(SHORT, Some(b's'), Some("short"), Arity::None, true),
row(UNREAD, Some(b'b'), Some("branch"), Arity::None, true),
row(UNREAD, None, Some("show-stash"), Arity::None, true),
row(UNREAD, None, Some("ahead-behind"), Arity::None, true),
row(PORCELAIN, None, Some("porcelain"), Arity::Optional, true),
row(LONG, None, Some("long"), Arity::None, true),
row(NULL, Some(b'z'), Some("null"), Arity::None, true),
row(
UNREAD,
Some(b'u'),
Some("untracked-files"),
Arity::Optional,
true,
),
row(UNREAD, None, Some("ignored"), Arity::Optional, true),
row(
UNREAD,
None,
Some("ignore-submodules"),
Arity::Optional,
true,
),
row(UNREAD, None, Some("column"), Arity::Optional, true),
row(UNREAD, None, Some("no-renames"), Arity::None, true),
row(
UNREAD,
Some(b'M'),
Some("find-renames"),
Arity::Optional,
false,
),
];
const ADVICE_KEY: &[u8] = b"advice.statushints";
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct StatusRegion {
pub machine_readable: bool,
pub wrapper: Vec<WrapperOccurrence>,
}
fn has_machine_format(parsed: &ParsedOptions) -> bool {
let mut machine: bool = false;
for occurrence in &parsed.occurrences {
if occurrence.id == SHORT || occurrence.id == PORCELAIN {
machine = !occurrence.negated;
}
if occurrence.id == LONG {
machine = false;
}
}
return machine;
}
pub fn parse_status_region(
region: &[OsString],
wrapper_flags: &[&[u8]],
) -> Result<StatusRegion, OptionError> {
let parsed: ParsedOptions = parse_options(region, STATUS_TABLE, DEFAULT_MODE, wrapper_flags)?;
return Ok(StatusRegion {
machine_readable: has_machine_format(&parsed) || is_enabled(&parsed, NULL),
wrapper: parsed.wrapper,
});
}
fn is_advice_key(key: &[u8]) -> bool {
return key.eq_ignore_ascii_case(ADVICE_KEY);
}
fn equals_index(bytes: &[u8], last: bool) -> Option<usize> {
let mut found: Option<usize> = None;
let mut index: usize = 0;
while index < bytes.len() {
if bytes[index] == b'=' {
found = Some(index);
if !last {
return found;
}
}
index += 1;
}
return found;
}
fn sets_advice_key(parameter: &[u8], from_environment: bool) -> bool {
if let Some(at) = equals_index(parameter, from_environment) {
return is_advice_key(¶meter[..at]);
}
return !from_environment && is_advice_key(parameter);
}
pub fn has_status_hints_override(global_prefix: &[OsString]) -> bool {
let mut awaiting_value: Option<&[u8]> = None;
for argument in global_prefix {
let token: &[u8] = argument.as_encoded_bytes();
if let Some(option) = awaiting_value {
awaiting_value = None;
if option == b"-c" && sets_advice_key(token, false) {
return true;
}
if option == b"--config-env" && sets_advice_key(token, true) {
return true;
}
continue;
}
if let Some(joined) = token.strip_prefix(b"--config-env=") {
if sets_advice_key(joined, true) {
return true;
}
continue;
}
if VALUE_OPTIONS.contains(&token) {
awaiting_value = Some(token);
}
}
return false;
}
#[cfg(test)]
#[path = "command_status_tests.rs"]
mod tests;