use crate::command_config_table::{
CONFIG_STOP_MODE, DISPLAY_ROWS, GET_FILTER_ROWS, GET_OTHER_ROWS, GLOBAL, LEGACY_ACTION_ROWS,
LEGACY_OTHER_ROWS, LIST, LIST_OTHER_ROWS, LOCATION_ROWS, SET_ROWS, SYSTEM, TYPE_ROWS,
UNSET_ROWS,
};
use crate::command_options::{
DEFAULT_MODE, OptionError, OptionSpec, ParseMode, ParsedOptions, WrapperOccurrence,
parse_options,
};
use crate::command_options_query::{is_enabled, is_stated};
use std::ffi::OsString;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ConfigForm {
List,
Get,
Set,
Unset,
RenameSection,
RemoveSection,
Edit,
Legacy,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConfigRegion {
pub form: ConfigForm,
pub global: bool,
pub system: bool,
pub lists: bool,
pub wrapper: Vec<WrapperOccurrence>,
}
fn form_of_word(word: &[u8]) -> Option<ConfigForm> {
let words: [(&[u8], ConfigForm); 7] = [
(b"list", ConfigForm::List),
(b"get", ConfigForm::Get),
(b"set", ConfigForm::Set),
(b"unset", ConfigForm::Unset),
(b"rename-section", ConfigForm::RenameSection),
(b"remove-section", ConfigForm::RemoveSection),
(b"edit", ConfigForm::Edit),
];
for (spelling, form) in words {
if spelling == word {
return Some(form);
}
}
return None;
}
pub fn config_table(form: ConfigForm) -> Vec<OptionSpec> {
let groups: &[&[OptionSpec]] = match form {
ConfigForm::List => &[LOCATION_ROWS, DISPLAY_ROWS, TYPE_ROWS, LIST_OTHER_ROWS],
ConfigForm::Get => &[
LOCATION_ROWS,
GET_FILTER_ROWS,
DISPLAY_ROWS,
TYPE_ROWS,
GET_OTHER_ROWS,
],
ConfigForm::Set => &[LOCATION_ROWS, TYPE_ROWS, SET_ROWS],
ConfigForm::Unset => &[LOCATION_ROWS, UNSET_ROWS],
ConfigForm::RenameSection | ConfigForm::RemoveSection | ConfigForm::Edit => {
&[LOCATION_ROWS]
}
ConfigForm::Legacy => &[
LOCATION_ROWS,
LEGACY_ACTION_ROWS,
DISPLAY_ROWS,
TYPE_ROWS,
LEGACY_OTHER_ROWS,
],
};
let mut table: Vec<OptionSpec> = Vec::<OptionSpec>::new();
for group in groups {
table.extend_from_slice(group);
}
return table;
}
pub fn parse_config_region(
region: &[OsString],
wrapper_flags: &[&[u8]],
) -> Result<ConfigRegion, OptionError> {
let mut wrapper: Vec<WrapperOccurrence> = Vec::<WrapperOccurrence>::new();
let mut first: usize = 0;
while first < region.len() {
let token: &[u8] = region[first].as_encoded_bytes();
let mut flag: usize = 0;
while flag < wrapper_flags.len() && wrapper_flags[flag] != token {
flag += 1;
}
if flag == wrapper_flags.len() {
break;
}
wrapper.push(WrapperOccurrence { flag, token: first });
first += 1;
}
let mut form: ConfigForm = ConfigForm::Legacy;
let mut offset: usize = first;
if let Some(found) = region.get(first) {
let word: &[u8] = found.as_encoded_bytes();
if let Some(named) = form_of_word(word) {
form = named;
offset = first + 1;
} else if word == b"--" {
offset = first + 1;
}
}
let mode: ParseMode = if form == ConfigForm::List || form == ConfigForm::Edit {
DEFAULT_MODE
} else {
CONFIG_STOP_MODE
};
let table: Vec<OptionSpec> = config_table(form);
let outcome: Result<ParsedOptions, OptionError> =
parse_options(®ion[offset..], table.as_slice(), mode, wrapper_flags);
let parsed: ParsedOptions = match outcome {
Ok(found) => found,
Err(refusal) => {
return Err(OptionError {
kind: refusal.kind,
token: refusal.token + offset,
});
}
};
for occurrence in &parsed.wrapper {
wrapper.push(WrapperOccurrence {
flag: occurrence.flag,
token: occurrence.token + offset,
});
}
return Ok(ConfigRegion {
form,
global: is_enabled(&parsed, GLOBAL),
system: is_enabled(&parsed, SYSTEM),
lists: form == ConfigForm::List || (form == ConfigForm::Legacy && is_stated(&parsed, LIST)),
wrapper,
});
}
#[cfg(test)]
#[path = "command_config_tests.rs"]
mod tests;