mirror of
https://github.com/dandavison/delta.git
synced 2024-10-04 03:47:53 +03:00
Compare commits
20 Commits
96dabb2018
...
fd5dcab06b
Author | SHA1 | Date | |
---|---|---|---|
|
fd5dcab06b | ||
|
0dd38d43f7 | ||
|
c384eed937 | ||
|
7dd279284b | ||
|
9b80e68904 | ||
|
a589ff9deb | ||
|
3f092c7e74 | ||
|
3ccdd2d21f | ||
|
df43b77fa5 | ||
|
c5696757c0 | ||
|
8220cefb3c | ||
|
46c72682d5 | ||
|
a66ac8e182 | ||
|
cba999a99f | ||
|
e1f3e618b7 | ||
|
5363030e96 | ||
|
9830f595b4 | ||
|
b595a2fe01 | ||
|
3a9c7ad296 | ||
|
9c4f98aef5 |
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -591,7 +591,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git-delta"
|
||||
version = "0.18.1"
|
||||
version = "0.18.2"
|
||||
dependencies = [
|
||||
"ansi_colours",
|
||||
"ansi_term",
|
||||
@ -1559,9 +1559,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.11"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
|
@ -8,7 +8,7 @@ edition = "2018"
|
||||
homepage = "https://github.com/dandavison/delta"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/dandavison/delta"
|
||||
version = "0.18.1"
|
||||
version = "0.18.2"
|
||||
|
||||
[[bin]]
|
||||
name = "delta"
|
||||
@ -55,7 +55,7 @@ syntect = "5.0.0"
|
||||
sysinfo = { version = "0.29.0", default-features = false, features = [] }
|
||||
terminal-colorsaurus = "0.4.1"
|
||||
unicode-segmentation = "1.10.1"
|
||||
unicode-width = "0.1.10"
|
||||
unicode-width = "=0.1.12"
|
||||
xdg = "2.4.1"
|
||||
|
||||
[lints.rust]
|
||||
|
@ -48,10 +48,9 @@ BUMP_VERSION_IN_DOCUMENTATION_LINKS_SENTINEL=.make-sentinels/bump-version-in-doc
|
||||
bump-version-in-documentation-links: $(BUMP_VERSION_IN_DOCUMENTATION_LINKS_SENTINEL)
|
||||
$(BUMP_VERSION_IN_DOCUMENTATION_LINKS_SENTINEL):
|
||||
sed -i -E "s,$$DELTA_OLD_VERSION,$$DELTA_NEW_VERSION,g" manual/src/full---help-output.md manual/src/installation.md
|
||||
rg -qF "$$DELTA_NEW_VERSION" manual/src/full---help-output.md
|
||||
rg -qF "$$DELTA_NEW_VERSION" manual/src/installation.md
|
||||
git add manual/src/full---help-output.md manual/src/installation.md
|
||||
git commit -m "Bump version in links to executables"
|
||||
git commit -m "Link to new binaries"
|
||||
touch $(BUMP_VERSION_IN_DOCUMENTATION_LINKS_SENTINEL)
|
||||
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
# Installation
|
||||
|
||||
You can download an executable for your system:
|
||||
[Linux (glibc)](https://github.com/dandavison/delta/releases/download/0.18.1/delta-0.18.1-x86_64-unknown-linux-gnu.tar.gz)
|
||||
[Linux (glibc)](https://github.com/dandavison/delta/releases/download/0.18.2/delta-0.18.2-x86_64-unknown-linux-gnu.tar.gz)
|
||||
|
|
||||
[Linux (musl)](https://github.com/dandavison/delta/releases/download/0.18.1/delta-0.18.1-x86_64-unknown-linux-musl.tar.gz)
|
||||
[Linux (musl)](https://github.com/dandavison/delta/releases/download/0.18.2/delta-0.18.2-x86_64-unknown-linux-musl.tar.gz)
|
||||
|
|
||||
[MacOS](https://github.com/dandavison/delta/releases/download/0.18.1/delta-0.18.1-x86_64-apple-darwin.tar.gz)
|
||||
[MacOS](https://github.com/dandavison/delta/releases/download/0.18.2/delta-0.18.2-x86_64-apple-darwin.tar.gz)
|
||||
|
|
||||
[Windows](https://github.com/dandavison/delta/releases/download/0.18.1/delta-0.18.1-x86_64-pc-windows-msvc.zip)
|
||||
[Windows](https://github.com/dandavison/delta/releases/download/0.18.2/delta-0.18.2-x86_64-pc-windows-msvc.zip)
|
||||
|
|
||||
[All](https://github.com/dandavison/delta/releases)
|
||||
|
||||
|
@ -11,6 +11,7 @@ use syntect::highlighting::Theme as SyntaxTheme;
|
||||
use syntect::parsing::SyntaxSet;
|
||||
|
||||
use crate::ansi::{ANSI_SGR_BOLD, ANSI_SGR_RESET, ANSI_SGR_UNDERLINE};
|
||||
use crate::color::ColorMode;
|
||||
use crate::config::delta_unreachable;
|
||||
use crate::env::DeltaEnv;
|
||||
use crate::git_config::GitConfig;
|
||||
@ -1180,7 +1181,7 @@ pub struct ComputedValues {
|
||||
pub background_color_extends_to_terminal_width: bool,
|
||||
pub decorations_width: Width,
|
||||
pub inspect_raw_lines: InspectRawLines,
|
||||
pub is_light_mode: bool,
|
||||
pub color_mode: ColorMode,
|
||||
pub paging_mode: PagingMode,
|
||||
pub syntax_set: SyntaxSet,
|
||||
pub syntax_theme: Option<SyntaxTheme>,
|
||||
|
60
src/color.rs
60
src/color.rs
@ -8,6 +8,7 @@ use syntect::highlighting::Color as SyntectColor;
|
||||
use crate::fatal;
|
||||
use crate::git_config::GitConfig;
|
||||
use crate::utils;
|
||||
use ColorMode::*;
|
||||
|
||||
pub fn parse_color(s: &str, true_color: bool, git_config: Option<&GitConfig>) -> Option<Color> {
|
||||
if s == "normal" {
|
||||
@ -105,39 +106,50 @@ fn ansi_16_color_number_to_name(n: u8) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_minus_background_color_default(is_light_mode: bool, is_true_color: bool) -> Color {
|
||||
match (is_light_mode, is_true_color) {
|
||||
(true, true) => LIGHT_THEME_MINUS_COLOR,
|
||||
(true, false) => LIGHT_THEME_MINUS_COLOR_256,
|
||||
(false, true) => DARK_THEME_MINUS_COLOR,
|
||||
(false, false) => DARK_THEME_MINUS_COLOR_256,
|
||||
/// The color mode determines some default color choices
|
||||
/// such as the diff background color or the palette used for blame.
|
||||
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ColorMode {
|
||||
#[default]
|
||||
/// Dark background with light text.
|
||||
Dark,
|
||||
/// Light background with dark text.
|
||||
Light,
|
||||
}
|
||||
|
||||
pub fn get_minus_background_color_default(mode: ColorMode, is_true_color: bool) -> Color {
|
||||
match (mode, is_true_color) {
|
||||
(Light, true) => LIGHT_THEME_MINUS_COLOR,
|
||||
(Light, false) => LIGHT_THEME_MINUS_COLOR_256,
|
||||
(Dark, true) => DARK_THEME_MINUS_COLOR,
|
||||
(Dark, false) => DARK_THEME_MINUS_COLOR_256,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_minus_emph_background_color_default(is_light_mode: bool, is_true_color: bool) -> Color {
|
||||
match (is_light_mode, is_true_color) {
|
||||
(true, true) => LIGHT_THEME_MINUS_EMPH_COLOR,
|
||||
(true, false) => LIGHT_THEME_MINUS_EMPH_COLOR_256,
|
||||
(false, true) => DARK_THEME_MINUS_EMPH_COLOR,
|
||||
(false, false) => DARK_THEME_MINUS_EMPH_COLOR_256,
|
||||
pub fn get_minus_emph_background_color_default(mode: ColorMode, is_true_color: bool) -> Color {
|
||||
match (mode, is_true_color) {
|
||||
(Light, true) => LIGHT_THEME_MINUS_EMPH_COLOR,
|
||||
(Light, false) => LIGHT_THEME_MINUS_EMPH_COLOR_256,
|
||||
(Dark, true) => DARK_THEME_MINUS_EMPH_COLOR,
|
||||
(Dark, false) => DARK_THEME_MINUS_EMPH_COLOR_256,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_plus_background_color_default(is_light_mode: bool, is_true_color: bool) -> Color {
|
||||
match (is_light_mode, is_true_color) {
|
||||
(true, true) => LIGHT_THEME_PLUS_COLOR,
|
||||
(true, false) => LIGHT_THEME_PLUS_COLOR_256,
|
||||
(false, true) => DARK_THEME_PLUS_COLOR,
|
||||
(false, false) => DARK_THEME_PLUS_COLOR_256,
|
||||
pub fn get_plus_background_color_default(mode: ColorMode, is_true_color: bool) -> Color {
|
||||
match (mode, is_true_color) {
|
||||
(Light, true) => LIGHT_THEME_PLUS_COLOR,
|
||||
(Light, false) => LIGHT_THEME_PLUS_COLOR_256,
|
||||
(Dark, true) => DARK_THEME_PLUS_COLOR,
|
||||
(Dark, false) => DARK_THEME_PLUS_COLOR_256,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_plus_emph_background_color_default(is_light_mode: bool, is_true_color: bool) -> Color {
|
||||
match (is_light_mode, is_true_color) {
|
||||
(true, true) => LIGHT_THEME_PLUS_EMPH_COLOR,
|
||||
(true, false) => LIGHT_THEME_PLUS_EMPH_COLOR_256,
|
||||
(false, true) => DARK_THEME_PLUS_EMPH_COLOR,
|
||||
(false, false) => DARK_THEME_PLUS_EMPH_COLOR_256,
|
||||
pub fn get_plus_emph_background_color_default(mode: ColorMode, is_true_color: bool) -> Color {
|
||||
match (mode, is_true_color) {
|
||||
(Light, true) => LIGHT_THEME_PLUS_EMPH_COLOR,
|
||||
(Light, false) => LIGHT_THEME_PLUS_EMPH_COLOR_256,
|
||||
(Dark, true) => DARK_THEME_PLUS_EMPH_COLOR,
|
||||
(Dark, false) => DARK_THEME_PLUS_EMPH_COLOR_256,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use syntect::parsing::SyntaxSet;
|
||||
|
||||
use crate::ansi;
|
||||
use crate::cli;
|
||||
use crate::color;
|
||||
use crate::color::{self, ColorMode};
|
||||
use crate::delta::State;
|
||||
use crate::fatal;
|
||||
use crate::features::navigate;
|
||||
@ -214,7 +214,7 @@ impl From<cli::Opt> for Config {
|
||||
));
|
||||
});
|
||||
|
||||
let blame_palette = make_blame_palette(opt.blame_palette, opt.computed.is_light_mode);
|
||||
let blame_palette = make_blame_palette(opt.blame_palette, opt.computed.color_mode);
|
||||
|
||||
if blame_palette.is_empty() {
|
||||
fatal("Option 'blame-palette' must not be empty.")
|
||||
@ -437,17 +437,17 @@ impl From<cli::Opt> for Config {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_blame_palette(blame_palette: Option<String>, is_light_mode: bool) -> Vec<String> {
|
||||
match (blame_palette, is_light_mode) {
|
||||
fn make_blame_palette(blame_palette: Option<String>, mode: ColorMode) -> Vec<String> {
|
||||
match (blame_palette, mode) {
|
||||
(Some(string), _) => string
|
||||
.split_whitespace()
|
||||
.map(|s| s.to_owned())
|
||||
.collect::<Vec<String>>(),
|
||||
(None, true) => color::LIGHT_THEME_BLAME_PALETTE
|
||||
(None, ColorMode::Light) => color::LIGHT_THEME_BLAME_PALETTE
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
(None, false) => color::DARK_THEME_BLAME_PALETTE
|
||||
(None, ColorMode::Dark) => color::DARK_THEME_BLAME_PALETTE
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
|
@ -3,6 +3,7 @@ use std::cmp::max;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::color::ColorMode::*;
|
||||
use crate::config;
|
||||
use crate::delta::State;
|
||||
use crate::features::hyperlinks;
|
||||
@ -38,26 +39,27 @@ pub fn make_feature() -> Vec<(String, OptionValueFunction)> {
|
||||
"line-numbers-minus-style",
|
||||
String,
|
||||
None,
|
||||
opt => if opt.computed.is_light_mode {
|
||||
"red".to_string()
|
||||
} else {
|
||||
"88".to_string()
|
||||
opt => match opt.computed.color_mode {
|
||||
Light => "red",
|
||||
Dark => "88",
|
||||
}
|
||||
),
|
||||
(
|
||||
"line-numbers-zero-style",
|
||||
String,
|
||||
None,
|
||||
opt => if opt.computed.is_light_mode {"#dddddd"} else {"#444444"}
|
||||
opt => match opt.computed.color_mode {
|
||||
Light => "#dddddd",
|
||||
Dark => "#444444",
|
||||
}
|
||||
),
|
||||
(
|
||||
"line-numbers-plus-style",
|
||||
String,
|
||||
None,
|
||||
opt => if opt.computed.is_light_mode {
|
||||
"green".to_string()
|
||||
} else {
|
||||
"28".to_string()
|
||||
opt => match opt.computed.color_mode {
|
||||
Light => "green",
|
||||
Dark => "28",
|
||||
}
|
||||
)
|
||||
])
|
||||
|
@ -14,7 +14,7 @@ use crate::format::{self, FormatStringSimple, Placeholder};
|
||||
use crate::format::{make_placeholder_regex, parse_line_number_format};
|
||||
use crate::paint::{self, BgShouldFill, StyleSectionSpecifier};
|
||||
use crate::style::Style;
|
||||
use crate::utils;
|
||||
use crate::utils::process;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BlameLineNumbers {
|
||||
@ -76,9 +76,8 @@ impl<'a> StateMachine<'a> {
|
||||
)?;
|
||||
|
||||
// Emit syntax-highlighted code
|
||||
if matches!(self.state, State::Unknown) {
|
||||
self.painter
|
||||
.set_syntax(utils::process::git_blame_filename().as_deref());
|
||||
if self.state == State::Unknown {
|
||||
self.painter.set_syntax(self.get_filename().as_deref());
|
||||
self.painter.set_highlighter();
|
||||
}
|
||||
self.state = State::Blame(key);
|
||||
@ -94,6 +93,13 @@ impl<'a> StateMachine<'a> {
|
||||
Ok(handled_line)
|
||||
}
|
||||
|
||||
fn get_filename(&self) -> Option<String> {
|
||||
match &*process::calling_process() {
|
||||
process::CallingProcess::GitBlame(command_line) => command_line.last_arg.clone(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn blame_metadata_style(
|
||||
&mut self,
|
||||
key: &str,
|
||||
|
@ -105,7 +105,7 @@ fn run_app() -> std::io::Result<i32> {
|
||||
Some(subcommands::show_themes::show_themes(
|
||||
opt.dark,
|
||||
opt.light,
|
||||
opt.computed.is_light_mode,
|
||||
opt.computed.color_mode,
|
||||
))
|
||||
} else if opt.show_colors {
|
||||
Some(subcommands::show_colors::show_colors())
|
||||
|
@ -237,7 +237,7 @@ pub fn set_options(
|
||||
// Setting ComputedValues
|
||||
set_widths_and_isatty(opt);
|
||||
set_true_color(opt);
|
||||
theme::set__is_light_mode__syntax_theme__syntax_set(opt, assets);
|
||||
theme::set__color_mode__syntax_theme__syntax_set(opt, assets);
|
||||
opt.computed.inspect_raw_lines =
|
||||
cli::InspectRawLines::from_str(&opt.inspect_raw_lines).unwrap();
|
||||
opt.computed.paging_mode = parse_paging_mode(&opt.paging_mode);
|
||||
|
@ -1,30 +1,33 @@
|
||||
//! Delta doesn't have a formal concept of a "theme". What it has is
|
||||
//!
|
||||
//! 1. The choice of "theme". This is the language syntax highlighting theme; you have to make this
|
||||
//! choice when using `bat` also.
|
||||
//! 2. The choice of "light vs dark mode". This determines whether the background colors should be
|
||||
//! chosen for a light or dark terminal background. (`bat` has no equivalent.)
|
||||
//!
|
||||
//! Basically:
|
||||
//! 1. The theme is specified by the `--syntax-theme` option. If this isn't supplied then it is specified
|
||||
//! by the `BAT_THEME` environment variable.
|
||||
//! 2. Light vs dark mode is specified by the `--light` or `--dark` options. If these aren't
|
||||
//! supplied then it detected from the terminal. If this fails it is inferred from the chosen theme.
|
||||
//!
|
||||
//! In the absence of other factors, the default assumes a dark terminal background.
|
||||
|
||||
use std::io::{stdout, IsTerminal};
|
||||
|
||||
/// Delta doesn't have a formal concept of a "theme". What it has is
|
||||
/// (a) the choice of syntax-highlighting theme
|
||||
/// (b) the choice of light-background-mode vs dark-background-mode, which determine certain
|
||||
/// default color choices
|
||||
/// This module sets those options. If the light/dark background mode choice is not made explicitly
|
||||
/// by the user, it is determined by the classification of the syntax theme into light-background
|
||||
/// vs dark-background syntax themes. If the user didn't choose a syntax theme, a dark-background
|
||||
/// default is selected.
|
||||
use bat;
|
||||
use bat::assets::HighlightingAssets;
|
||||
#[cfg(not(test))]
|
||||
use terminal_colorsaurus::{color_scheme, QueryOptions};
|
||||
|
||||
use crate::cli::{self, DetectDarkLight};
|
||||
use crate::color::{ColorMode, ColorMode::*};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn set__is_light_mode__syntax_theme__syntax_set(
|
||||
opt: &mut cli::Opt,
|
||||
assets: HighlightingAssets,
|
||||
) {
|
||||
let syntax_theme_name_from_bat_theme = &opt.env.bat_theme;
|
||||
let (is_light_mode, syntax_theme_name) = get_is_light_mode_and_syntax_theme_name(
|
||||
opt.syntax_theme.as_ref(),
|
||||
syntax_theme_name_from_bat_theme.as_ref(),
|
||||
get_is_light(opt),
|
||||
);
|
||||
opt.computed.is_light_mode = is_light_mode;
|
||||
pub fn set__color_mode__syntax_theme__syntax_set(opt: &mut cli::Opt, assets: HighlightingAssets) {
|
||||
let (color_mode, syntax_theme_name) =
|
||||
get_color_mode_and_syntax_theme_name(opt.syntax_theme.as_ref(), get_color_mode(opt));
|
||||
opt.computed.color_mode = color_mode;
|
||||
|
||||
opt.computed.syntax_theme = if is_no_syntax_highlighting_syntax_theme_name(&syntax_theme_name) {
|
||||
None
|
||||
@ -38,6 +41,14 @@ pub fn is_light_syntax_theme(theme: &str) -> bool {
|
||||
LIGHT_SYNTAX_THEMES.contains(&theme) || theme.to_lowercase().contains("light")
|
||||
}
|
||||
|
||||
pub fn color_mode_from_syntax_theme(theme: &str) -> ColorMode {
|
||||
if is_light_syntax_theme(theme) {
|
||||
ColorMode::Light
|
||||
} else {
|
||||
ColorMode::Dark
|
||||
}
|
||||
}
|
||||
|
||||
const LIGHT_SYNTAX_THEMES: [&str; 7] = [
|
||||
"Catppuccin Latte",
|
||||
"GitHub",
|
||||
@ -55,69 +66,34 @@ fn is_no_syntax_highlighting_syntax_theme_name(theme_name: &str) -> bool {
|
||||
theme_name.to_lowercase() == "none"
|
||||
}
|
||||
|
||||
/// Return a (theme_name, is_light_mode) tuple.
|
||||
/// Return a (theme_name, color_mode) tuple.
|
||||
/// theme_name == None in return value means syntax highlighting is disabled.
|
||||
///
|
||||
/// There are two types of color choices that have to be made:
|
||||
|
||||
/// 1. The choice of "theme". This is the language syntax highlighting theme; you have to make this
|
||||
/// choice when using `bat` also.
|
||||
/// 2. The choice of "light vs dark mode". This determines whether the background colors should be
|
||||
/// chosen for a light or dark terminal background. (`bat` has no equivalent.)
|
||||
///
|
||||
/// Basically:
|
||||
/// 1. The theme is specified by the `--syntax-theme` option. If this isn't supplied then it is specified
|
||||
/// by the `BAT_THEME` environment variable.
|
||||
/// 2. Light vs dark mode is specified by the `--light` or `--dark` options. If these aren't
|
||||
/// supplied then it is inferred from the chosen theme.
|
||||
///
|
||||
/// In the absence of other factors, the default assumes a dark terminal background.
|
||||
///
|
||||
/// Specifically, the rules are as follows:
|
||||
///
|
||||
/// | --theme | $BAT_THEME | --light/--dark | Behavior |
|
||||
/// |------------|------------|----------------|----------------------------------------------------------------------------|
|
||||
/// | - | - | - | default dark theme, dark mode |
|
||||
/// | some_theme | (IGNORED) | - | some_theme with light/dark mode inferred accordingly |
|
||||
/// | - | BAT_THEME | - | BAT_THEME, with light/dark mode inferred accordingly |
|
||||
/// | - | - | yes | default light/dark theme, light/dark mode |
|
||||
/// | some_theme | (IGNORED) | yes | some_theme, light/dark mode (even if some_theme conflicts with light/dark) |
|
||||
/// | - | BAT_THEME | yes | BAT_THEME, light/dark mode (even if BAT_THEME conflicts with light/dark) |
|
||||
fn get_is_light_mode_and_syntax_theme_name(
|
||||
theme_arg: Option<&String>,
|
||||
bat_theme_env_var: Option<&String>,
|
||||
light_mode: bool,
|
||||
) -> (bool, String) {
|
||||
match (theme_arg, bat_theme_env_var, light_mode) {
|
||||
(None, None, false) => (false, DEFAULT_DARK_SYNTAX_THEME.to_string()),
|
||||
(Some(theme_name), _, false) => (is_light_syntax_theme(theme_name), theme_name.to_string()),
|
||||
(None, Some(theme_name), false) => {
|
||||
(is_light_syntax_theme(theme_name), theme_name.to_string())
|
||||
}
|
||||
(None, None, true) => (true, DEFAULT_LIGHT_SYNTAX_THEME.to_string()),
|
||||
(Some(theme_name), _, is_light_mode) => (is_light_mode, theme_name.to_string()),
|
||||
(None, Some(theme_name), is_light_mode) => (is_light_mode, theme_name.to_string()),
|
||||
fn get_color_mode_and_syntax_theme_name(
|
||||
syntax_theme: Option<&String>,
|
||||
mode: Option<ColorMode>,
|
||||
) -> (ColorMode, String) {
|
||||
match (syntax_theme, mode) {
|
||||
(Some(theme), None) => (color_mode_from_syntax_theme(theme), theme.to_string()),
|
||||
(Some(theme), Some(mode)) => (mode, theme.to_string()),
|
||||
(None, None | Some(Dark)) => (Dark, DEFAULT_DARK_SYNTAX_THEME.to_string()),
|
||||
(None, Some(Light)) => (Light, DEFAULT_LIGHT_SYNTAX_THEME.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_is_light(opt: &cli::Opt) -> bool {
|
||||
get_is_light_opt(opt)
|
||||
.or_else(|| should_detect_dark_light(opt).then(detect_light_mode))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_is_light_opt(opt: &cli::Opt) -> Option<bool> {
|
||||
fn get_color_mode(opt: &cli::Opt) -> Option<ColorMode> {
|
||||
if opt.light {
|
||||
Some(true)
|
||||
Some(Light)
|
||||
} else if opt.dark {
|
||||
Some(false)
|
||||
Some(Dark)
|
||||
} else if should_detect_color_mode(opt) {
|
||||
detect_color_mode()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`cli::Opt::detect_dark_light`] for a detailed explanation.
|
||||
fn should_detect_dark_light(opt: &cli::Opt) -> bool {
|
||||
fn should_detect_color_mode(opt: &cli::Opt) -> bool {
|
||||
match opt.detect_dark_light {
|
||||
DetectDarkLight::Auto => opt.color_only || stdout().is_terminal(),
|
||||
DetectDarkLight::Always => true,
|
||||
@ -126,19 +102,26 @@ fn should_detect_dark_light(opt: &cli::Opt) -> bool {
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
fn detect_light_mode() -> bool {
|
||||
use terminal_colorsaurus::{color_scheme, ColorScheme, QueryOptions};
|
||||
color_scheme(QueryOptions::default()).unwrap_or_default() == ColorScheme::Light
|
||||
fn detect_color_mode() -> Option<ColorMode> {
|
||||
color_scheme(QueryOptions::default())
|
||||
.ok()
|
||||
.map(ColorMode::from)
|
||||
}
|
||||
|
||||
impl From<terminal_colorsaurus::ColorScheme> for ColorMode {
|
||||
fn from(value: terminal_colorsaurus::ColorScheme) -> Self {
|
||||
match value {
|
||||
terminal_colorsaurus::ColorScheme::Dark => ColorMode::Dark,
|
||||
terminal_colorsaurus::ColorScheme::Light => ColorMode::Light,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn detect_light_mode() -> bool {
|
||||
LIGHT_MODE_IN_TESTS
|
||||
fn detect_color_mode() -> Option<ColorMode> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) const LIGHT_MODE_IN_TESTS: bool = false;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -148,41 +131,24 @@ mod tests {
|
||||
// TODO: Test influence of BAT_THEME env var. E.g. see utils::process::tests::FakeParentArgs.
|
||||
#[test]
|
||||
fn test_syntax_theme_selection() {
|
||||
#[derive(PartialEq)]
|
||||
enum Mode {
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
for (
|
||||
syntax_theme,
|
||||
mode, // (--light, --dark)
|
||||
expected_syntax_theme,
|
||||
expected_mode,
|
||||
) in vec![
|
||||
(None, None, DEFAULT_DARK_SYNTAX_THEME, Mode::Dark),
|
||||
(Some("GitHub"), None, "GitHub", Mode::Light),
|
||||
(Some("GitHub"), None, "GitHub", Mode::Light),
|
||||
(
|
||||
None,
|
||||
Some(Mode::Light),
|
||||
DEFAULT_LIGHT_SYNTAX_THEME,
|
||||
Mode::Light,
|
||||
),
|
||||
(
|
||||
None,
|
||||
Some(Mode::Dark),
|
||||
DEFAULT_DARK_SYNTAX_THEME,
|
||||
Mode::Dark,
|
||||
),
|
||||
(
|
||||
None,
|
||||
Some(Mode::Light),
|
||||
DEFAULT_LIGHT_SYNTAX_THEME,
|
||||
Mode::Light,
|
||||
),
|
||||
(None, Some(Mode::Light), "GitHub", Mode::Light),
|
||||
(Some("none"), None, "none", Mode::Dark),
|
||||
(Some("None"), Some(Mode::Light), "none", Mode::Light),
|
||||
(None, None, DEFAULT_DARK_SYNTAX_THEME, Dark),
|
||||
(Some("GitHub"), None, "GitHub", Light),
|
||||
(Some("Nord"), None, "Nord", Dark),
|
||||
(None, Some(Dark), DEFAULT_DARK_SYNTAX_THEME, Dark),
|
||||
(None, Some(Light), DEFAULT_LIGHT_SYNTAX_THEME, Light),
|
||||
(Some("GitHub"), Some(Light), "GitHub", Light),
|
||||
(Some("GitHub"), Some(Dark), "GitHub", Dark),
|
||||
(Some("Nord"), Some(Light), "Nord", Light),
|
||||
(Some("Nord"), Some(Dark), "Nord", Dark),
|
||||
(Some("none"), None, "none", Dark),
|
||||
(Some("none"), Some(Dark), "none", Dark),
|
||||
(Some("None"), Some(Light), "none", Light),
|
||||
] {
|
||||
let mut args = vec![];
|
||||
if let Some(syntax_theme) = syntax_theme {
|
||||
@ -198,10 +164,10 @@ mod tests {
|
||||
args.push("never");
|
||||
}
|
||||
match mode {
|
||||
Some(Mode::Light) => {
|
||||
Some(Light) => {
|
||||
args.push("--light");
|
||||
}
|
||||
Some(Mode::Dark) => {
|
||||
Some(Dark) => {
|
||||
args.push("--dark");
|
||||
}
|
||||
None => {}
|
||||
@ -225,31 +191,19 @@ mod tests {
|
||||
}
|
||||
assert_eq!(
|
||||
config.minus_style.ansi_term_style.background.unwrap(),
|
||||
color::get_minus_background_color_default(
|
||||
expected_mode == Mode::Light,
|
||||
is_true_color
|
||||
)
|
||||
color::get_minus_background_color_default(expected_mode, is_true_color)
|
||||
);
|
||||
assert_eq!(
|
||||
config.minus_emph_style.ansi_term_style.background.unwrap(),
|
||||
color::get_minus_emph_background_color_default(
|
||||
expected_mode == Mode::Light,
|
||||
is_true_color
|
||||
)
|
||||
color::get_minus_emph_background_color_default(expected_mode, is_true_color)
|
||||
);
|
||||
assert_eq!(
|
||||
config.plus_style.ansi_term_style.background.unwrap(),
|
||||
color::get_plus_background_color_default(
|
||||
expected_mode == Mode::Light,
|
||||
is_true_color
|
||||
)
|
||||
color::get_plus_background_color_default(expected_mode, is_true_color)
|
||||
);
|
||||
assert_eq!(
|
||||
config.plus_emph_style.ansi_term_style.background.unwrap(),
|
||||
color::get_plus_emph_background_color_default(
|
||||
expected_mode == Mode::Light,
|
||||
is_true_color
|
||||
)
|
||||
color::get_plus_emph_background_color_default(expected_mode, is_true_color)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +261,9 @@ impl<'p> Painter<'p> {
|
||||
line.push_str(
|
||||
#[allow(clippy::unnecessary_to_owned)]
|
||||
&fill_style
|
||||
.paint(" ".repeat(config.available_terminal_width - text_width))
|
||||
.paint(
|
||||
" ".repeat(config.available_terminal_width.saturating_sub(text_width)),
|
||||
)
|
||||
.to_string(),
|
||||
);
|
||||
} else if line_is_empty {
|
||||
|
@ -115,15 +115,14 @@ fn parse_as_reference_to_git_config(style_string: &str, opt: &cli::Opt) -> Style
|
||||
}
|
||||
|
||||
fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleReference>) {
|
||||
let is_light_mode = opt.computed.is_light_mode;
|
||||
let color_mode = opt.computed.color_mode;
|
||||
let true_color = opt.computed.true_color;
|
||||
let minus_style = style_from_str(
|
||||
&opt.minus_style,
|
||||
Some(Style::from_colors(
|
||||
None,
|
||||
Some(color::get_minus_background_color_default(
|
||||
is_light_mode,
|
||||
true_color,
|
||||
color_mode, true_color,
|
||||
)),
|
||||
)),
|
||||
None,
|
||||
@ -136,8 +135,7 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe
|
||||
Some(Style::from_colors(
|
||||
None,
|
||||
Some(color::get_minus_emph_background_color_default(
|
||||
is_light_mode,
|
||||
true_color,
|
||||
color_mode, true_color,
|
||||
)),
|
||||
)),
|
||||
None,
|
||||
@ -160,8 +158,7 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe
|
||||
Some(Style::from_colors(
|
||||
None,
|
||||
Some(color::get_minus_background_color_default(
|
||||
is_light_mode,
|
||||
true_color,
|
||||
color_mode, true_color,
|
||||
)),
|
||||
)),
|
||||
None,
|
||||
@ -176,8 +173,7 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe
|
||||
Some(Style::from_colors(
|
||||
None,
|
||||
Some(color::get_plus_background_color_default(
|
||||
is_light_mode,
|
||||
true_color,
|
||||
color_mode, true_color,
|
||||
)),
|
||||
)),
|
||||
None,
|
||||
@ -190,8 +186,7 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe
|
||||
Some(Style::from_colors(
|
||||
None,
|
||||
Some(color::get_plus_emph_background_color_default(
|
||||
is_light_mode,
|
||||
true_color,
|
||||
color_mode, true_color,
|
||||
)),
|
||||
)),
|
||||
None,
|
||||
@ -214,8 +209,7 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe
|
||||
Some(Style::from_colors(
|
||||
None,
|
||||
Some(color::get_plus_background_color_default(
|
||||
is_light_mode,
|
||||
true_color,
|
||||
color_mode, true_color,
|
||||
)),
|
||||
)),
|
||||
None,
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::cli;
|
||||
use crate::color::{ColorMode, ColorMode::*};
|
||||
use crate::config;
|
||||
use crate::delta;
|
||||
use crate::env::DeltaEnv;
|
||||
use crate::options::theme::is_light_syntax_theme;
|
||||
use crate::options::theme::color_mode_from_syntax_theme;
|
||||
use crate::utils;
|
||||
use crate::utils::bat::output::{OutputType, PagingMode};
|
||||
use clap::Parser;
|
||||
@ -41,19 +42,19 @@ pub fn show_syntax_themes() -> std::io::Result<()> {
|
||||
let opt = make_opt();
|
||||
|
||||
if !(opt.dark || opt.light) {
|
||||
_show_syntax_themes(opt, false, &mut writer, stdin_data.as_ref())?;
|
||||
_show_syntax_themes(make_opt(), true, &mut writer, stdin_data.as_ref())?;
|
||||
_show_syntax_themes(opt, Dark, &mut writer, stdin_data.as_ref())?;
|
||||
_show_syntax_themes(make_opt(), Light, &mut writer, stdin_data.as_ref())?;
|
||||
} else if opt.light {
|
||||
_show_syntax_themes(opt, true, &mut writer, stdin_data.as_ref())?;
|
||||
_show_syntax_themes(opt, Light, &mut writer, stdin_data.as_ref())?;
|
||||
} else {
|
||||
_show_syntax_themes(opt, false, &mut writer, stdin_data.as_ref())?
|
||||
_show_syntax_themes(opt, Dark, &mut writer, stdin_data.as_ref())?
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _show_syntax_themes(
|
||||
mut opt: cli::Opt,
|
||||
is_light_mode: bool,
|
||||
color_mode: ColorMode,
|
||||
writer: &mut dyn Write,
|
||||
stdin: Option<&Vec<u8>>,
|
||||
) -> std::io::Result<()> {
|
||||
@ -80,14 +81,14 @@ index f38589a..0f1bb83 100644
|
||||
}
|
||||
};
|
||||
|
||||
opt.computed.is_light_mode = is_light_mode;
|
||||
opt.computed.color_mode = color_mode;
|
||||
let mut config = config::Config::from(opt);
|
||||
let title_style = ansi_term::Style::new().bold();
|
||||
let assets = utils::bat::assets::load_highlighting_assets();
|
||||
|
||||
for syntax_theme in assets
|
||||
.themes()
|
||||
.filter(|t| is_light_syntax_theme(t) == is_light_mode)
|
||||
.filter(|t| color_mode_from_syntax_theme(t) == color_mode)
|
||||
{
|
||||
writeln!(
|
||||
writer,
|
||||
@ -121,7 +122,7 @@ mod tests {
|
||||
let opt = integration_test_utils::make_options_from_args(&[]);
|
||||
|
||||
let mut writer = Cursor::new(vec![0; 1024]);
|
||||
_show_syntax_themes(opt, true, &mut writer, None).unwrap();
|
||||
_show_syntax_themes(opt, Light, &mut writer, None).unwrap();
|
||||
let mut s = String::new();
|
||||
writer.rewind().unwrap();
|
||||
writer.read_to_string(&mut s).unwrap();
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::io::{self, ErrorKind, IsTerminal, Read};
|
||||
|
||||
use crate::cli;
|
||||
use crate::color::ColorMode;
|
||||
use crate::config;
|
||||
use crate::delta;
|
||||
use crate::env::DeltaEnv;
|
||||
@ -8,7 +9,7 @@ use crate::git_config;
|
||||
use crate::options::get::get_themes;
|
||||
use crate::utils::bat::output::{OutputType, PagingMode};
|
||||
|
||||
pub fn show_themes(dark: bool, light: bool, computed_theme_is_light: bool) -> std::io::Result<()> {
|
||||
pub fn show_themes(dark: bool, light: bool, color_mode: ColorMode) -> std::io::Result<()> {
|
||||
use std::io::BufReader;
|
||||
|
||||
use bytelines::ByteLines;
|
||||
@ -58,8 +59,8 @@ pub fn show_themes(dark: bool, light: bool, computed_theme_is_light: bool) -> st
|
||||
let is_light_theme = opt.light;
|
||||
let config = config::Config::from(opt);
|
||||
|
||||
if (!computed_theme_is_light && is_dark_theme)
|
||||
|| (computed_theme_is_light && is_light_theme)
|
||||
if (color_mode == ColorMode::Dark && is_dark_theme)
|
||||
|| (color_mode == ColorMode::Light && is_light_theme)
|
||||
|| (dark && light)
|
||||
{
|
||||
writeln!(writer, "\n\nTheme: {}\n", title_style.paint(theme))?;
|
||||
|
@ -2137,6 +2137,31 @@ src/align.rs:71: impl<'a> Alignment<'a> { │
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test] #[ignore]
|
||||
fn test_long_line_underflow() {
|
||||
let output = DeltaTest::with_args(&["--width" , "111", "--zero-style", "syntax #FFFFFF"]).with_input(GIT_DIFF_LONG_LINE).skip_header();
|
||||
|
||||
assert_snapshot!(output, @r###"
|
||||
foobar
|
||||
───────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
────────────────────────────────┐
|
||||
14: function UNDERFLOW_EXEC() { │
|
||||
────────────────────────────────┘
|
||||
XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
|
||||
}
|
||||
|
||||
|
||||
|
||||
echo "=== VALIDATE UNDERFLOW"
|
||||
/usr/local/bin/check_underflow
|
||||
|
||||
# this is an example of the underflow error
|
||||
echo "=== UNDERFLOW_EXEC"
|
||||
UNDERFLOW_EXEC -i foobar.yaml
|
||||
"###);
|
||||
}
|
||||
|
||||
const GIT_DIFF_SINGLE_HUNK: &str = "\
|
||||
commit 94907c0f136f46dc46ffae2dc92dca9af7eb7c2e
|
||||
Author: Dan Davison <dandavison7@gmail.com>
|
||||
@ -3125,4 +3150,30 @@ index 53f98b6..14d6caa 100644
|
||||
三æäöø€ÆÄÖ〇Øß三
|
||||
¶
|
||||
";
|
||||
|
||||
const GIT_DIFF_LONG_LINE: &str = r#"\
|
||||
commit XXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
Author: LUCIANO FURTADO <lrfurtado@gmail.com>
|
||||
Date: Tue Jun 25 14:07:31 2024 -0500
|
||||
|
||||
Ref: https://github.com/dandavison/delta/issues/1760
|
||||
|
||||
diff --git a/foobar b/foobar
|
||||
index 185a33cd5b..123f893935 100755
|
||||
--- a/foobar
|
||||
+++ b/foobar
|
||||
@@ -14,6 +14,11 @@ function UNDERFLOW_EXEC() {
|
||||
XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
|
||||
}
|
||||
|
||||
+
|
||||
+
|
||||
+echo "=== VALIDATE UNDERFLOW"
|
||||
+/usr/local/bin/check_underflow
|
||||
+
|
||||
# this is an example of the underflow error
|
||||
echo "=== UNDERFLOW_EXEC"
|
||||
UNDERFLOW_EXEC -i foobar.yaml
|
||||
|
||||
"#;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ pub enum CallingProcess {
|
||||
GitShow(CommandLine, Option<String>), // element 2 is filename
|
||||
GitLog(CommandLine),
|
||||
GitReflog(CommandLine),
|
||||
GitBlame(CommandLine),
|
||||
GitGrep(CommandLine),
|
||||
OtherGrep, // rg, grep, ag, ack, etc
|
||||
None, // no matching process could be found
|
||||
@ -26,7 +27,9 @@ impl CallingProcess {
|
||||
CallingProcess::GitDiff(cmd) if cmd.long_options.contains("--relative") => true,
|
||||
CallingProcess::GitShow(cmd, _) if cmd.long_options.contains("--relative") => true,
|
||||
CallingProcess::GitLog(cmd) if cmd.long_options.contains("--relative") => true,
|
||||
CallingProcess::GitGrep(_) | CallingProcess::OtherGrep => true,
|
||||
CallingProcess::GitBlame(_)
|
||||
| CallingProcess::GitGrep(_)
|
||||
| CallingProcess::OtherGrep => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -36,7 +39,7 @@ impl CallingProcess {
|
||||
pub struct CommandLine {
|
||||
pub long_options: HashSet<String>,
|
||||
pub short_options: HashSet<String>,
|
||||
last_arg: Option<String>,
|
||||
pub last_arg: Option<String>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@ -110,36 +113,6 @@ pub enum ProcessArgs<T> {
|
||||
OtherProcess,
|
||||
}
|
||||
|
||||
pub fn git_blame_filename() -> Option<String> {
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename)
|
||||
}
|
||||
|
||||
pub fn guess_git_blame_filename(args: &[String]) -> ProcessArgs<String> {
|
||||
let all_args = args.iter().map(|s| s.as_str());
|
||||
|
||||
// See git(1) and git-blame(1). Some arguments separate their parameter with space or '=', e.g.
|
||||
// --date 2015 or --date=2015.
|
||||
let git_blame_options_with_parameter =
|
||||
"-C -c -L --since --ignore-rev --ignore-revs-file --contents --reverse --date";
|
||||
|
||||
let selected_args =
|
||||
skip_uninteresting_args(all_args, git_blame_options_with_parameter.split(' '));
|
||||
|
||||
match selected_args.as_slice() {
|
||||
[git, "blame", .., last_arg] if is_git_binary(git) => {
|
||||
match Path::new(last_arg)
|
||||
.file_name()
|
||||
.map(|filename| filename.to_string_lossy().to_string())
|
||||
{
|
||||
Some(filename) => ProcessArgs::Args(filename),
|
||||
None => ProcessArgs::ArgError,
|
||||
}
|
||||
}
|
||||
[git, "blame"] if is_git_binary(git) => ProcessArgs::ArgError,
|
||||
_ => ProcessArgs::OtherProcess,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn describe_calling_process(args: &[String]) -> ProcessArgs<CallingProcess> {
|
||||
let mut args = args.iter().map(|s| s.as_str());
|
||||
|
||||
@ -155,7 +128,12 @@ pub fn describe_calling_process(args: &[String]) -> ProcessArgs<CallingProcess>
|
||||
Some(command) => match Path::new(command).file_stem() {
|
||||
Some(s) if s.to_str().map(is_git_binary).unwrap_or(false) => {
|
||||
let mut args = args.skip_while(|s| {
|
||||
*s != "diff" && *s != "show" && *s != "log" && *s != "reflog" && *s != "grep"
|
||||
*s != "diff"
|
||||
&& *s != "show"
|
||||
&& *s != "log"
|
||||
&& *s != "reflog"
|
||||
&& *s != "grep"
|
||||
&& *s != "blame"
|
||||
});
|
||||
match args.next() {
|
||||
Some("diff") => {
|
||||
@ -184,6 +162,9 @@ pub fn describe_calling_process(args: &[String]) -> ProcessArgs<CallingProcess>
|
||||
Some("grep") => {
|
||||
ProcessArgs::Args(CallingProcess::GitGrep(parse_command_line(args)))
|
||||
}
|
||||
Some("blame") => {
|
||||
ProcessArgs::Args(CallingProcess::GitBlame(parse_command_line(args)))
|
||||
}
|
||||
_ => {
|
||||
// It's git, but not a subcommand that we parse. Don't
|
||||
// look at any more processes.
|
||||
@ -223,49 +204,19 @@ fn is_git_binary(git: &str) -> bool {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
// Skip all arguments starting with '-' from `args_it`. Also skip all arguments listed in
|
||||
// `skip_this_plus_parameter` plus their respective next argument.
|
||||
// Keep all arguments once a '--' is encountered.
|
||||
// (Note that some arguments work with and without '=': '--foo' 'bar' / '--foo=bar')
|
||||
fn skip_uninteresting_args<'a, 'b, ArgsI, SkipI>(
|
||||
mut args_it: ArgsI,
|
||||
skip_this_plus_parameter: SkipI,
|
||||
) -> Vec<&'a str>
|
||||
where
|
||||
ArgsI: Iterator<Item = &'a str>,
|
||||
SkipI: Iterator<Item = &'b str>,
|
||||
{
|
||||
let arg_follows_space: HashSet<&'b str> = skip_this_plus_parameter.into_iter().collect();
|
||||
|
||||
let mut result = Vec::new();
|
||||
loop {
|
||||
match args_it.next() {
|
||||
None => break result,
|
||||
Some("--") => {
|
||||
result.extend(args_it);
|
||||
break result;
|
||||
}
|
||||
Some(arg) if arg_follows_space.contains(arg) => {
|
||||
let _skip_parameter = args_it.next();
|
||||
}
|
||||
Some(arg) if !arg.starts_with('-') => {
|
||||
result.push(arg);
|
||||
}
|
||||
Some(_) => { /* skip: --these -and --also=this */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Given `--aa val -bc -d val e f -- ...` return
|
||||
// ({"--aa"}, {"-b", "-c", "-d"})
|
||||
fn parse_command_line<'a>(args: impl Iterator<Item = &'a str>) -> CommandLine {
|
||||
let mut long_options = HashSet::new();
|
||||
let mut short_options = HashSet::new();
|
||||
let mut last_arg = None;
|
||||
let mut after_double_dash = false;
|
||||
|
||||
for s in args {
|
||||
if s == "--" {
|
||||
break;
|
||||
if after_double_dash {
|
||||
last_arg = Some(s);
|
||||
} else if s == "--" {
|
||||
after_double_dash = true;
|
||||
} else if s.starts_with("--") {
|
||||
long_options.insert(s.split('=').next().unwrap().to_owned());
|
||||
} else if let Some(suffix) = s.strip_prefix('-') {
|
||||
@ -598,6 +549,7 @@ pub mod tests {
|
||||
With(usize, Rc<Vec<T>>),
|
||||
None,
|
||||
Invalid,
|
||||
ErrorAlreadyHandled,
|
||||
}
|
||||
|
||||
// When calling `FakeParentArgs::get()`, it can return `Some(values)` which were set earlier
|
||||
@ -648,24 +600,39 @@ pub mod tests {
|
||||
TlsState::With(n, args) => TlsState::With(*n + 1, Rc::clone(args)),
|
||||
TlsState::None => TlsState::None,
|
||||
TlsState::Invalid => TlsState::Invalid,
|
||||
TlsState::ErrorAlreadyHandled => TlsState::ErrorAlreadyHandled,
|
||||
});
|
||||
|
||||
match old_value {
|
||||
TlsState::Once(args) | TlsState::Scope(args) => Some(args),
|
||||
TlsState::With(n, args) if n < args.len() => Some(args[n].clone()),
|
||||
TlsState::None => None,
|
||||
TlsState::Invalid | TlsState::With(_, _) => Self::error("get"),
|
||||
TlsState::Invalid | TlsState::With(_, _) | TlsState::ErrorAlreadyHandled => {
|
||||
Self::error("get");
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
pub fn are_set() -> bool {
|
||||
FAKE_ARGS.with(|a| *a.borrow() != TlsState::None)
|
||||
FAKE_ARGS.with(|a| {
|
||||
*a.borrow() != TlsState::None && *a.borrow() != TlsState::ErrorAlreadyHandled
|
||||
})
|
||||
}
|
||||
fn error(where_: &str) -> ! {
|
||||
panic!(
|
||||
"test logic error (in {}): wrong FakeParentArgs scope?",
|
||||
where_
|
||||
);
|
||||
fn error(where_: &str) {
|
||||
FAKE_ARGS.with(|a| {
|
||||
let old_value = a.replace(TlsState::ErrorAlreadyHandled);
|
||||
|
||||
match old_value {
|
||||
TlsState::ErrorAlreadyHandled => (),
|
||||
_ => {
|
||||
panic!(
|
||||
"test logic error (in {}): wrong FakeParentArgs scope?",
|
||||
where_
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
impl Drop for FakeParentArgs {
|
||||
@ -680,59 +647,12 @@ pub mod tests {
|
||||
}
|
||||
}
|
||||
TlsState::Once(_) | TlsState::None => Self::error("drop"),
|
||||
TlsState::Scope(_) | TlsState::Invalid => {}
|
||||
TlsState::Scope(_) | TlsState::Invalid | TlsState::ErrorAlreadyHandled => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_guess_git_blame_filename() {
|
||||
use ProcessArgs::Args;
|
||||
|
||||
fn make_string_vec(args: &[&str]) -> Vec<String> {
|
||||
args.iter().map(|&x| x.to_owned()).collect::<Vec<String>>()
|
||||
}
|
||||
let args = make_string_vec(&["git", "blame", "hello", "world.txt"]);
|
||||
assert_eq!(guess_git_blame_filename(&args), Args("world.txt".into()));
|
||||
|
||||
let args = make_string_vec(&[
|
||||
"git",
|
||||
"blame",
|
||||
"-s",
|
||||
"-f",
|
||||
"hello.txt",
|
||||
"--date=2015",
|
||||
"--date",
|
||||
"now",
|
||||
]);
|
||||
assert_eq!(guess_git_blame_filename(&args), Args("hello.txt".into()));
|
||||
|
||||
let args = make_string_vec(&["git", "blame", "-s", "-f", "--", "hello.txt"]);
|
||||
assert_eq!(guess_git_blame_filename(&args), Args("hello.txt".into()));
|
||||
|
||||
let args = make_string_vec(&["git", "blame", "--", "--not.an.argument"]);
|
||||
assert_eq!(
|
||||
guess_git_blame_filename(&args),
|
||||
Args("--not.an.argument".into())
|
||||
);
|
||||
|
||||
let args = make_string_vec(&["foo", "bar", "-a", "--123", "not.git"]);
|
||||
assert_eq!(guess_git_blame_filename(&args), ProcessArgs::OtherProcess);
|
||||
|
||||
let args = make_string_vec(&["git", "blame", "--help.txt"]);
|
||||
assert_eq!(guess_git_blame_filename(&args), ProcessArgs::ArgError);
|
||||
|
||||
let args = make_string_vec(&["git", "-c", "a=b", "blame", "main.rs"]);
|
||||
assert_eq!(guess_git_blame_filename(&args), Args("main.rs".into()));
|
||||
|
||||
let args = make_string_vec(&["git", "blame", "README"]);
|
||||
assert_eq!(guess_git_blame_filename(&args), Args("README".into()));
|
||||
|
||||
let args = make_string_vec(&["git", "blame", ""]);
|
||||
assert_eq!(guess_git_blame_filename(&args), ProcessArgs::ArgError);
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct FakeProc {
|
||||
#[allow(dead_code)]
|
||||
@ -817,46 +737,71 @@ pub mod tests {
|
||||
{
|
||||
let _args = FakeParentArgs::once("git blame hello");
|
||||
assert_eq!(
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename),
|
||||
Some("hello".into())
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("hello".into())
|
||||
}))
|
||||
);
|
||||
}
|
||||
{
|
||||
let _args = FakeParentArgs::once("git blame world.txt");
|
||||
assert_eq!(
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename),
|
||||
Some("world.txt".into())
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("world.txt".into())
|
||||
}))
|
||||
);
|
||||
}
|
||||
{
|
||||
let _args = FakeParentArgs::for_scope("git blame hello world.txt");
|
||||
assert_eq!(
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename),
|
||||
Some("world.txt".into())
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("world.txt".into())
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "test logic error (in get): wrong FakeParentArgs scope?")]
|
||||
fn test_process_testing_assert() {
|
||||
let _args = FakeParentArgs::once("git blame do.not.panic");
|
||||
assert_eq!(
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename),
|
||||
Some("do.not.panic".into())
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("do.not.panic".into())
|
||||
}))
|
||||
);
|
||||
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename);
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_process_testing_assert_never_used() {
|
||||
#[should_panic(expected = "test logic error (in drop): wrong FakeParentArgs scope?")]
|
||||
fn test_process_testing_assert_once_never_used() {
|
||||
let _args = FakeParentArgs::once("never used");
|
||||
}
|
||||
|
||||
// causes a panic while panicking, so can't test:
|
||||
// let _args = FakeParentArgs::for_scope(&"never used");
|
||||
// let _args = FakeParentArgs::once(&"never used");
|
||||
#[test]
|
||||
#[should_panic(expected = "test logic error (in once): wrong FakeParentArgs scope?")]
|
||||
fn test_process_testing_assert_for_scope_never_used() {
|
||||
let _args = FakeParentArgs::for_scope(&"never used");
|
||||
let _args = FakeParentArgs::once(&"never used");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "test logic error (in for_scope): wrong FakeParentArgs scope?")]
|
||||
fn test_process_testing_assert_once_never_used2() {
|
||||
let _args = FakeParentArgs::once(&"never used");
|
||||
let _args = FakeParentArgs::for_scope(&"never used");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -865,50 +810,70 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_testing_n_times_panic() {
|
||||
fn test_process_testing_n_times() {
|
||||
let _args = FakeParentArgs::with(&["git blame once", "git blame twice"]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename),
|
||||
Some("once".into())
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("once".into())
|
||||
}))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename),
|
||||
Some("twice".into())
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("twice".into())
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "test logic error (in drop with): wrong FakeParentArgs scope?")]
|
||||
fn test_process_testing_n_times_unused() {
|
||||
let _args = FakeParentArgs::with(&["git blame once", "git blame twice"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "test logic error (in drop with): wrong FakeParentArgs scope?")]
|
||||
fn test_process_testing_n_times_underused() {
|
||||
let _args = FakeParentArgs::with(&["git blame once", "git blame twice"]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename),
|
||||
Some("once".into())
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("once".into())
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[ignore]
|
||||
#[should_panic(expected = "test logic error (in get): wrong FakeParentArgs scope?")]
|
||||
fn test_process_testing_n_times_overused() {
|
||||
let _args = FakeParentArgs::with(&["git blame once"]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename),
|
||||
Some("once".into())
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("once".into())
|
||||
}))
|
||||
);
|
||||
// ignored: dropping causes a panic while panicking, so can't test
|
||||
calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename);
|
||||
calling_process_cmdline(ProcInfo::new(), describe_calling_process);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_blame_no_parent_found() {
|
||||
fn test_describe_calling_process_blame() {
|
||||
let no_processes = MockProcInfo::with(&[]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(no_processes, describe_calling_process),
|
||||
None
|
||||
);
|
||||
|
||||
let two_trees = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, "git blame src/main.rs", Some(2)),
|
||||
@ -916,43 +881,119 @@ pub mod tests {
|
||||
(5, 100, "delta", Some(4)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(two_trees, guess_git_blame_filename),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_blame_info_with_parent() {
|
||||
let no_processes = MockProcInfo::with(&[]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(no_processes, guess_git_blame_filename),
|
||||
calling_process_cmdline(two_trees, describe_calling_process),
|
||||
None
|
||||
);
|
||||
|
||||
let no_options_command_line = CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("hello.txt".to_string()),
|
||||
};
|
||||
let parent = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, "git blame hello.txt", Some(2)),
|
||||
(4, 100, "delta", Some(3)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(parent, guess_git_blame_filename),
|
||||
Some("hello.txt".into())
|
||||
calling_process_cmdline(parent, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(no_options_command_line.clone()))
|
||||
);
|
||||
|
||||
let parent = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, "git blame -- hello.txt", Some(2)),
|
||||
(4, 100, "delta", Some(3)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(parent, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(no_options_command_line.clone()))
|
||||
);
|
||||
|
||||
let parent = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, "git blame -- --not.an.argument", Some(2)),
|
||||
(4, 100, "delta", Some(3)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(parent, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("--not.an.argument".to_string()),
|
||||
}))
|
||||
);
|
||||
|
||||
let parent = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, "git blame --help.txt", Some(2)),
|
||||
(4, 100, "delta", Some(3)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(parent, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: ["--help.txt".into()].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: None,
|
||||
}))
|
||||
);
|
||||
|
||||
let parent = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, "git blame --", Some(2)),
|
||||
(4, 100, "delta", Some(3)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(parent, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: None,
|
||||
}))
|
||||
);
|
||||
|
||||
let parent = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, "Git.exe blame hello.txt", Some(2)),
|
||||
(4, 100, "delta", Some(3)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(parent, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(no_options_command_line.clone()))
|
||||
);
|
||||
|
||||
let git_blame_command =
|
||||
"git -c a=b blame -fnb --incremental -t --color-by-age -M --since=3.weeks --contents annotation.txt -C -C2 hello.txt";
|
||||
|
||||
// here -C2 is parsed as -C and -2. It doesn't really matters because we only use last_arg from options
|
||||
// to determine the file type.
|
||||
let expected_result = Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: set(&["--incremental", "--color-by-age", "--since", "--contents"]),
|
||||
short_options: set(&["-f", "-n", "-b", "-t", "-M", "-C", "-2"]),
|
||||
last_arg: Some("hello.txt".to_string()),
|
||||
}));
|
||||
|
||||
let parent = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, git_blame_command, Some(2)),
|
||||
(4, 100, "delta", Some(3)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(parent, describe_calling_process),
|
||||
expected_result
|
||||
);
|
||||
|
||||
let grandparent = MockProcInfo::with(&[
|
||||
(2, 100, "-shell", None),
|
||||
(3, 100, "git blame src/main.rs", Some(2)),
|
||||
(3, 100, git_blame_command, Some(2)),
|
||||
(4, 100, "call_delta.sh", Some(3)),
|
||||
(5, 100, "delta", Some(4)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(grandparent, guess_git_blame_filename),
|
||||
Some("main.rs".into())
|
||||
calling_process_cmdline(grandparent, describe_calling_process),
|
||||
expected_result
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_blame_info_with_sibling() {
|
||||
let sibling = MockProcInfo::with(&[
|
||||
(2, 100, "-xterm", None),
|
||||
(3, 100, "-shell", Some(2)),
|
||||
@ -960,8 +1001,12 @@ pub mod tests {
|
||||
(5, 100, "delta", Some(3)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(sibling, guess_git_blame_filename),
|
||||
Some("main.rs".into())
|
||||
calling_process_cmdline(sibling, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("src/main.rs".into())
|
||||
}))
|
||||
);
|
||||
|
||||
let indirect_sibling = MockProcInfo::with(&[
|
||||
@ -978,8 +1023,12 @@ pub mod tests {
|
||||
(20, 100, "delta", Some(5)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(indirect_sibling, guess_git_blame_filename),
|
||||
Some("main.abc".into())
|
||||
calling_process_cmdline(indirect_sibling, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: set(&["--correct"]),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("src/main.abc".into())
|
||||
}))
|
||||
);
|
||||
|
||||
let indirect_sibling2 = MockProcInfo::with(&[
|
||||
@ -991,8 +1040,12 @@ pub mod tests {
|
||||
(20, 100, "delta", Some(5)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(indirect_sibling2, guess_git_blame_filename),
|
||||
Some("main.def".into())
|
||||
calling_process_cmdline(indirect_sibling2, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("src/main.def".into())
|
||||
}))
|
||||
);
|
||||
|
||||
// 3 blame processes, 2 with matching start times, pick the one with lower
|
||||
@ -1010,8 +1063,12 @@ pub mod tests {
|
||||
(20, 100, "delta", Some(5)),
|
||||
]);
|
||||
assert_eq!(
|
||||
calling_process_cmdline(indirect_sibling_start_times, guess_git_blame_filename),
|
||||
Some("main.this".into())
|
||||
calling_process_cmdline(indirect_sibling_start_times, describe_calling_process),
|
||||
Some(CallingProcess::GitBlame(CommandLine {
|
||||
long_options: [].into(),
|
||||
short_options: [].into(),
|
||||
last_arg: Some("src/main.this".into())
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user