pub(crate) const TRUE_WORDS: [&str; 3] = ["true", "yes", "on"];
pub(crate) const FALSE_WORDS: [&str; 3] = ["false", "no", "off"];
pub(crate) const BOOLEAN_KEYS: [&str; 49] = [
"color.advice",
"color.pager",
"commitgraph.readchangedpaths",
"core.commitgraph",
"core.filemode",
"core.ignorecase",
"core.ignorestat",
"core.lockfilepid",
"core.multipackindex",
"core.precomposeunicode",
"core.protecthfs",
"core.protectntfs",
"core.quotepath",
"core.sparsecheckout",
"core.sparsecheckoutcone",
"core.symlinks",
"core.trustctime",
"core.usereplacerefs",
"core.warnambiguousrefs",
"diff.autorefreshindex",
"diff.indentheuristic",
"diff.mnemonicprefix",
"diff.noprefix",
"diff.relative",
"diff.suppressblankempty",
"diff.trustexitcode",
"feature.experimental",
"feature.manyfiles",
"fetch.writecommitgraph",
"format.encodeemailheaders",
"fsmonitor.allowremote",
"gc.writecommitgraph",
"grep.column",
"grep.extendedregexp",
"grep.fullname",
"grep.linenumber",
"index.skiphash",
"index.sparse",
"log.abbrevcommit",
"log.follow",
"log.mailmap",
"log.showroot",
"log.showsignature",
"pack.readreverseindex",
"pack.usebitmapboundarytraversal",
"pack.usepathwalk",
"pack.usesparse",
"sparse.expectfilesoutsideofpatterns",
"user.useconfigonly",
];
pub(crate) const TEXT_KEYS: [&str; 21] = [
"attr.tree",
"author.email",
"author.name",
"committer.email",
"committer.name",
"core.askpass",
"core.checkroundtripencoding",
"core.editor",
"core.untrackedcache",
"core.whitespace",
"diff.dstprefix",
"diff.external",
"diff.srcprefix",
"diff.wordregex",
"format.subjectprefix",
"i18n.commitencoding",
"i18n.logoutputencoding",
"mailmap.blob",
"remote.pushdefault",
"user.email",
"user.name",
];
pub(crate) const PATHNAME_KEYS: [&str; 5] = ["core.attributesfile", "core.excludesfile", "core.hookspath", "fsmonitor.socketdir", "mailmap.file"];
pub(crate) const DRIVER_BOOLEAN_NAMES: [&str; 3] = ["binary", "cachetextconv", "trustexitcode"];
pub(crate) const DRIVER_TEXT_NAMES: [&str; 4] = ["command", "textconv", "wordregex", "xfuncname"];
pub(crate) const REMOTE_BOOLEAN_NAMES: [&str; 6] = ["mirror", "promisor", "prune", "prunetags", "skipdefaultupdate", "skipfetchall"];
pub(crate) const REMOTE_TEXT_NAMES: [&str; 12] = [
"negotiationinclude",
"negotiationrestrict",
"partialclonefilter",
"proxy",
"proxyauthmethod",
"pushurl",
"receivepack",
"serveroption",
"tagopt",
"uploadpack",
"url",
"vcs",
];
pub(crate) const GREP_COLOR_SLOTS: [&str; 10] = [
"column",
"context",
"filename",
"function",
"linenumber",
"match",
"matchcontext",
"matchselected",
"selected",
"separator",
];
pub(crate) const PLAIN_COLOR_WORDS: [&str; 2] = ["normal", "default"];
pub(crate) const BRIGHT_COLOR_WORDS: [&str; 8] = ["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"];
pub(crate) const ATTRIBUTE_WORDS: [&str; 7] = ["bold", "dim", "ul", "blink", "reverse", "italic", "strike"];
#[derive(Clone, Copy)]
pub(crate) enum Kind {
Boolean,
BooleanOr(&'static [&'static str]),
IntegerOrBoolean,
Integer { low: i64, high: i64 },
Text,
Pathname,
OneOf { words: &'static [&'static str], empty: bool },
Words { words: &'static [&'static str], empty: bool, negatable: bool },
Color,
Abbreviation,
CommentText,
Refspec,
OffOrBuiltinDaemon,
TraceTarget,
Refused,
}
pub(crate) const MINIMUM_ABBREVIATION: i64 = 4;
pub(crate) const MAXIMUM_ABBREVIATION: i64 = 64;
pub(crate) const COMPRESSION: Kind = Kind::Integer { low: -1, high: 9 };
pub(crate) const NON_NEGATIVE: Kind = Kind::Integer { low: 0, high: i32::MAX as i64 };
pub(crate) const SIZE: Kind = Kind::Integer { low: 0, high: i32::MAX as i64 };
pub(crate) fn split_key(key: &str) -> Option<(&str, Option<&str>, &str)> {
let (section, rest) = key.split_once('.')?;
return Some(match rest.rsplit_once('.') {
Some((subsection, name)) => (section, Some(subsection), name),
None => (section, None, rest),
});
}
pub(crate) fn kind_of(key: &str) -> Option<Kind> {
let (section, subsection, name) = split_key(key)?;
if section == "advice" && subsection.is_none() {
return Some(Kind::Boolean);
}
if subsection.is_none() {
if BOOLEAN_KEYS.contains(&key) {
return Some(Kind::Boolean);
}
if TEXT_KEYS.contains(&key) {
return Some(Kind::Text);
}
if PATHNAME_KEYS.contains(&key) {
return Some(Kind::Pathname);
}
return plain_kind(key);
}
return match (section, name) {
("branch", "merge" | "pushremote" | "remote") => Some(Kind::Text),
("diff", _) if DRIVER_BOOLEAN_NAMES.contains(&name) => Some(Kind::Boolean),
("diff", _) if DRIVER_TEXT_NAMES.contains(&name) => Some(Kind::Text),
("remote", _) if REMOTE_BOOLEAN_NAMES.contains(&name) => Some(Kind::Boolean),
("remote", _) if REMOTE_TEXT_NAMES.contains(&name) => Some(Kind::Text),
("remote", "followremotehead") => Some(Kind::OneOf { words: &["create", "warn", "always", "never"], empty: false }),
("remote", "fetch" | "push") => Some(Kind::Refspec),
("url", "insteadof" | "pushinsteadof") => Some(Kind::Text),
("color", _) => color_kind(subsection, name),
_ => None,
};
}
pub(crate) fn color_kind(subsection: Option<&str>, name: &str) -> Option<Kind> {
return match subsection {
Some("diff" | "decorate" | "advice") => Some(Kind::Color),
Some("grep") if GREP_COLOR_SLOTS.contains(&name) => Some(Kind::Color),
Some("grep") => Some(Kind::Refused),
_ => None,
};
}
pub(crate) fn plain_kind(key: &str) -> Option<Kind> {
return Some(match key {
"branch.autosetupmerge" => Kind::BooleanOr(&["always", "inherit", "simple"]),
"branch.autosetuprebase" => Kind::OneOf { words: &["never", "local", "remote", "always"], empty: false },
"color.ui" | "color.diff" | "color.grep" => Kind::BooleanOr(&["always", "never", "auto"]),
"commitgraph.changedpathsversion" | "commitgraph.generationversion" => NON_NEGATIVE,
"core.abbrev" => Kind::Abbreviation,
"core.autocrlf" => Kind::BooleanOr(&["input"]),
"core.bigfilethreshold" | "core.deltabasecachelimit" | "core.packedgitlimit" | "core.packedgitwindowsize" => SIZE,
"core.checkstat" => Kind::OneOf { words: &["default", "minimal"], empty: false },
"core.commentchar" | "core.commentstring" => Kind::CommentText,
"core.compression" | "core.loosecompression" | "pack.compression" => COMPRESSION,
"core.createobject" => Kind::OneOf { words: &["rename", "link"], empty: false },
"core.fsmonitor" => Kind::OffOrBuiltinDaemon,
"trace2.normaltarget" | "trace2.eventtarget" | "trace2.perftarget" => Kind::TraceTarget,
"core.fsync" => Kind::Words {
words: &["loose-object", "pack", "pack-metadata", "commit-graph", "index", "objects", "reference", "derived-metadata", "committed", "added", "all", "none"],
empty: false,
negatable: true,
},
"core.fsyncmethod" => Kind::OneOf { words: &["fsync", "writeout-only", "batch"], empty: false },
"core.fsyncobjectfiles" | "diff.dirstat" => Kind::Refused,
"core.maxtreedepth" | "diff.context" | "diff.interhunkcontext" | "diff.renamelimit" | "diff.statgraphwidth" | "diff.statnamewidth" | "format.filenamemaxlength" => NON_NEGATIVE,
"core.safecrlf" => Kind::BooleanOr(&["warn"]),
"diff.algorithm" => Kind::OneOf { words: &["default", "myers", "minimal", "patience", "histogram"], empty: false },
"diff.colormoved" => Kind::BooleanOr(&["default", "blocks", "zebra", "dimmed-zebra", "plain"]),
"diff.colormovedws" => Kind::Words {
words: &["no", "ignore-space-at-eol", "ignore-space-change", "ignore-all-space", "allow-indentation-change"],
empty: false,
negatable: false,
},
"diff.ignoresubmodules" => Kind::OneOf { words: &["none", "untracked", "dirty", "all"], empty: false },
"diff.renames" => Kind::BooleanOr(&["copy", "copies"]),
"diff.submodule" => Kind::OneOf { words: &["log", "short", "diff"], empty: false },
"diff.wserrorhighlight" => Kind::Words { words: &["old", "new", "context", "all", "default", "none"], empty: true, negatable: false },
"fetch.negotiationalgorithm" => Kind::OneOf { words: &["skipping", "noop", "consecutive", "default"], empty: false },
"format.pretty" => Kind::OneOf { words: &["oneline", "short", "medium", "full", "fuller", "reference", "email", "raw", "mboxrd"], empty: true },
"grep.patterntype" => Kind::OneOf { words: &["default", "basic", "extended", "fixed", "perl"], empty: false },
"index.threads" => Kind::IntegerOrBoolean,
"index.version" => Kind::Integer { low: 2, high: 4 },
"log.date" => Kind::OneOf {
words: &["relative", "local", "iso", "iso8601", "iso-strict", "iso8601-strict", "rfc", "rfc2822", "short", "raw", "human", "unix", "default"],
empty: false,
},
"log.diffmerges" => Kind::OneOf {
words: &["off", "none", "on", "m", "first-parent", "1", "separate", "combined", "c", "dense-combined", "cc", "remerge", "r"],
empty: false,
},
"pack.packsizelimit" => SIZE,
"push.default" => Kind::OneOf { words: &["nothing", "matching", "simple", "upstream", "tracking", "current"], empty: false },
"transfer.credentialsinurl" => Kind::OneOf { words: &["allow", "warn", "die"], empty: false },
_ => return None,
});
}