##// END OF EJS Templates
rust-filepatterns: export glob_to_re function...
rust-filepatterns: export glob_to_re function Making this function public should not risk freezing the internal API, and it can be useful for all downstream code that needs to perform glob matching against byte strings, such as RHGitaly where it will be useful to match on branches and tags.

File last commit:

r50826:fba29dee default
r52363:406b413e stable
Show More
color.rs
250 lines | 7.3 KiB | application/rls-services+xml | RustLexer
use crate::ui::formatted;
use crate::ui::plain;
use format_bytes::write_bytes;
use hg::config::Config;
use hg::config::ConfigOrigin;
use hg::errors::HgError;
use std::collections::HashMap;
pub type Effect = u32;
pub type EffectsMap = HashMap<Vec<u8>, Vec<Effect>>;
macro_rules! effects {
($( $name: ident: $value: expr ,)+) => {
#[allow(non_upper_case_globals)]
mod effects {
$(
pub const $name: super::Effect = $value;
)+
}
fn effect(name: &[u8]) -> Option<Effect> {
$(
if name == stringify!($name).as_bytes() {
Some(effects::$name)
} else
)+
{
None
}
}
};
}
effects! {
none: 0,
black: 30,
red: 31,
green: 32,
yellow: 33,
blue: 34,
magenta: 35,
cyan: 36,
white: 37,
bold: 1,
italic: 3,
underline: 4,
inverse: 7,
dim: 2,
black_background: 40,
red_background: 41,
green_background: 42,
yellow_background: 43,
blue_background: 44,
purple_background: 45,
cyan_background: 46,
white_background: 47,
}
macro_rules! default_styles {
($( $key: expr => [$($value: expr),*],)+) => {
fn default_styles() -> EffectsMap {
use effects::*;
let mut map = HashMap::new();
$(
map.insert($key[..].to_owned(), vec![$( $value ),*]);
)+
map
}
};
}
default_styles! {
b"grep.match" => [red, bold],
b"grep.linenumber" => [green],
b"grep.rev" => [blue],
b"grep.sep" => [cyan],
b"grep.filename" => [magenta],
b"grep.user" => [magenta],
b"grep.date" => [magenta],
b"grep.inserted" => [green, bold],
b"grep.deleted" => [red, bold],
b"bookmarks.active" => [green],
b"branches.active" => [none],
b"branches.closed" => [black, bold],
b"branches.current" => [green],
b"branches.inactive" => [none],
b"diff.changed" => [white],
b"diff.deleted" => [red],
b"diff.deleted.changed" => [red, bold, underline],
b"diff.deleted.unchanged" => [red],
b"diff.diffline" => [bold],
b"diff.extended" => [cyan, bold],
b"diff.file_a" => [red, bold],
b"diff.file_b" => [green, bold],
b"diff.hunk" => [magenta],
b"diff.inserted" => [green],
b"diff.inserted.changed" => [green, bold, underline],
b"diff.inserted.unchanged" => [green],
b"diff.tab" => [],
b"diff.trailingwhitespace" => [bold, red_background],
b"changeset.public" => [],
b"changeset.draft" => [],
b"changeset.secret" => [],
b"diffstat.deleted" => [red],
b"diffstat.inserted" => [green],
b"formatvariant.name.mismatchconfig" => [red],
b"formatvariant.name.mismatchdefault" => [yellow],
b"formatvariant.name.uptodate" => [green],
b"formatvariant.repo.mismatchconfig" => [red],
b"formatvariant.repo.mismatchdefault" => [yellow],
b"formatvariant.repo.uptodate" => [green],
b"formatvariant.config.special" => [yellow],
b"formatvariant.config.default" => [green],
b"formatvariant.default" => [],
b"histedit.remaining" => [red, bold],
b"ui.addremove.added" => [green],
b"ui.addremove.removed" => [red],
b"ui.error" => [red],
b"ui.prompt" => [yellow],
b"log.changeset" => [yellow],
b"patchbomb.finalsummary" => [],
b"patchbomb.from" => [magenta],
b"patchbomb.to" => [cyan],
b"patchbomb.subject" => [green],
b"patchbomb.diffstats" => [],
b"rebase.rebased" => [blue],
b"rebase.remaining" => [red, bold],
b"resolve.resolved" => [green, bold],
b"resolve.unresolved" => [red, bold],
b"shelve.age" => [cyan],
b"shelve.newest" => [green, bold],
b"shelve.name" => [blue, bold],
b"status.added" => [green, bold],
b"status.clean" => [none],
b"status.copied" => [none],
b"status.deleted" => [cyan, bold, underline],
b"status.ignored" => [black, bold],
b"status.modified" => [blue, bold],
b"status.removed" => [red, bold],
b"status.unknown" => [magenta, bold, underline],
b"tags.normal" => [green],
b"tags.local" => [black, bold],
b"upgrade-repo.requirement.preserved" => [cyan],
b"upgrade-repo.requirement.added" => [green],
b"upgrade-repo.requirement.removed" => [red],
}
fn parse_effect(config_key: &[u8], effect_name: &[u8]) -> Option<Effect> {
let found = effect(effect_name);
if found.is_none() {
// TODO: have some API for warnings
// TODO: handle IO errors during warnings
let stderr = std::io::stderr();
let _ = write_bytes!(
&mut stderr.lock(),
b"ignoring unknown color/effect '{}' \
(configured in color.{})\n",
effect_name,
config_key,
);
}
found
}
fn effects_from_config(config: &Config) -> EffectsMap {
let mut styles = default_styles();
for (key, _value) in config.iter_section(b"color") {
if !key.contains(&b'.')
|| key.starts_with(b"color.")
|| key.starts_with(b"terminfo.")
{
continue;
}
// `unwrap` shouldn’t panic since we just got this key from
// iteration
let list = config.get_list(b"color", key).unwrap();
let parsed = list
.iter()
.filter_map(|name| parse_effect(key, name))
.collect();
styles.insert(key.to_owned(), parsed);
}
styles
}
enum ColorMode {
// TODO: support other modes
Ansi,
}
impl ColorMode {
// Similar to _modesetup in mercurial/color.py
fn get(config: &Config) -> Result<Option<Self>, HgError> {
if plain(Some("color")) {
return Ok(None);
}
let enabled_default = b"auto";
// `origin` is only used when `!auto`, so its default doesn’t matter
let (enabled, origin) = config
.get_with_origin(b"ui", b"color")
.unwrap_or((enabled_default, &ConfigOrigin::CommandLineColor));
if enabled == b"debug" {
return Err(HgError::unsupported("debug color mode"));
}
let auto = enabled == b"auto";
let always = if !auto {
let enabled_bool = config.get_bool(b"ui", b"color")?;
if !enabled_bool {
return Ok(None);
}
enabled == b"always" || *origin == ConfigOrigin::CommandLineColor
} else {
false
};
let formatted = always
|| (std::env::var_os("TERM").unwrap_or_default() != "dumb"
&& formatted(config)?);
let mode_default = b"auto";
let mode = config.get(b"color", b"mode").unwrap_or(mode_default);
if formatted {
match mode {
b"ansi" | b"auto" => Ok(Some(ColorMode::Ansi)),
// TODO: support other modes
_ => Err(HgError::UnsupportedFeature(format!(
"color mode {}",
String::from_utf8_lossy(mode)
))),
}
} else {
Ok(None)
}
}
}
pub struct ColorConfig {
pub styles: EffectsMap,
}
impl ColorConfig {
// Similar to _modesetup in mercurial/color.py
pub fn new(config: &Config) -> Result<Option<Self>, HgError> {
Ok(ColorMode::get(config)?.map(|ColorMode::Ansi| ColorConfig {
styles: effects_from_config(config),
}))
}
}