Skip to content

Commit

Permalink
Handle git blame output
Browse files Browse the repository at this point in the history
Fixes #426

Partial versions of these changes were previously in master and then
reverted multiple times.

See #746
0745f85
3aab5d1
  • Loading branch information
dandavison committed Nov 14, 2021
1 parent 91d7d79 commit 6719cf8
Show file tree
Hide file tree
Showing 13 changed files with 506 additions and 1 deletion.
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ name = "delta"
path = "src/main.rs"

[dependencies]
chrono = "0.4.19"
chrono-humanize = "0.2.1"
ansi_colours = "1.0.4"
ansi_term = "0.12.1"
atty = "0.2.14"
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
show = delta
log = delta
reflog = delta
blame = delta # see default-language to enable `git blame` syntax highlighting

[interactive]
diffFilter = delta --color-only
Expand Down Expand Up @@ -152,6 +153,7 @@ Here's what `git show` can look like with git configured to use delta:
- `diff-highlight` and `diff-so-fancy` emulation modes
- Stylable box/line decorations to draw attention to commit, file and hunk header sections.
- Support for Git's `--color-moved` feature.
- Customizable `git blame` with syntax highlighting (`--hyperlinks` formats commits as links to GitHub/GitLab/Bitbucket etc)
- Code can be copied directly from the diff (`-/+` markers are removed by default).
- `n` and `N` keybindings to move between files in large diffs, and between diffs in `log -p` views (`--navigate`)
- Commit hashes can be formatted as terminal [hyperlinks](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda) to the GitHub/GitLab/Bitbucket page (`--hyperlinks`).
Expand Down Expand Up @@ -400,6 +402,28 @@ In contrast, the long replacement line in the right panel overflows by almost an
For control over the details of line wrapping, see `--wrap-max-lines`, `--wrap-left-symbol`, `--wrap-right-symbol`, `--wrap-right-percent`, `--wrap-right-prefix-symbol`, `--inline-hint-style`.
Line wrapping was implemented by @th1000s.

### git blame

Set delta as the pager for `git blame`, along with the standard diff-generating git operations:

```gitconfig
[pager]
diff = delta
show = delta
log = delta
reflog = delta
blame = delta # see default-language to enable `git blame` syntax highlighting
```

However, in order to activate syntax highlighting of `git blame` output, you must tell delta which language the file is written in by using the `default-language` option.
If you are working in a repository that mostly contains files in a single language, the most convenient way to do this is by editing the _repository-specific_ git config file, i.e. the one at `/path/to/repo/.git/config`, as opposed to the one in your home directory:
Add an entry like this, but using

```gitconfig
[delta]
default-language = rs # substitute the language file extension you want here!
```

### "Features": named groups of settings

All delta options can go under the `[delta]` section in your git config file. However, you can also use named "features" to keep things organized: these are sections in git config like `[delta "my-feature"]`. Here's an example using two custom features:
Expand Down Expand Up @@ -486,6 +510,12 @@ In order to support this feature, Delta has to look at the raw colors it receive

Use the `navigate` feature to activate navigation keybindings. In this mode, pressing `n` will jump forward to the next file in the diff, and `N` will jump backwards. If you are viewing multiple commits (e.g. via `git log -p`) then navigation will also visit commit boundaries.

### Git blame

Delta will render `git blame` output in its own way, if you have `pager.blame = delta` set in your `gitconfig`. Example:

<table><tr><td><img width=300px src="https://user-images.githubusercontent.com/52205/140330813-91b198af-c396-4c5e-9a30-26ee35b78e7e.png" alt="image" /></td></tr></table>

### 24 bit color (truecolor)

Delta looks best if your terminal application supports 24 bit colors. See https://github.com/termstandard/colors#readme. For example, on MacOS, iTerm2 supports 24-bit colors but Terminal.app does not.
Expand Down
21 changes: 21 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,27 @@ pub struct Opt {
/// (underline), 'ol' (overline), or the combination 'ul ol'.
pub hunk_header_decoration_style: String,

/// Format string for git blame commit metadata. Available placeholders are
/// "{timestamp}", "{author}", and "{commit}".
#[structopt(
long = "blame-format",
default_value = "{timestamp:<15} {author:<15.14} {commit:<8} │ "
)]
pub blame_format: String,

/// Background colors used for git blame lines (space-separated string).
/// Lines added by the same commit are painted with the same color; colors
/// are recycled as needed.
#[structopt(long = "blame-palette")]
pub blame_palette: Option<String>,

/// Format of `git blame` timestamp in raw git output received by delta.
#[structopt(
long = "blame-timestamp-format",
default_value = "%Y-%m-%d %H:%M:%S %z"
)]
pub blame_timestamp_format: String,

/// Default language used for syntax highlighting when this cannot be
/// inferred from a filename. It will typically make sense to set this in
/// per-repository git config (.git/config)
Expand Down
6 changes: 6 additions & 0 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,9 @@ const DARK_THEME_PLUS_COLOR_256: Color = Color::Fixed(22);
const DARK_THEME_PLUS_EMPH_COLOR: Color = Color::RGB(0x00, 0x60, 0x00);

const DARK_THEME_PLUS_EMPH_COLOR_256: Color = Color::Fixed(28);

// blame

pub const LIGHT_THEME_BLAME_PALETTE: &[&str] = &["#FFFFFF", "#DDDDDD", "#BBBBBB"];

pub const DARK_THEME_BLAME_PALETTE: &[&str] = &["#000000", "#222222", "#444444"];
25 changes: 25 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ fn adapt_wrap_max_lines_argument(arg: String) -> usize {
pub struct Config {
pub available_terminal_width: usize,
pub background_color_extends_to_terminal_width: bool,
pub blame_format: String,
pub blame_palette: Vec<String>,
pub blame_timestamp_format: String,
pub color_only: bool,
pub commit_regex: Regex,
pub commit_style: Style,
Expand Down Expand Up @@ -213,6 +216,8 @@ impl From<cli::Opt> for Config {
_ => *style::GIT_DEFAULT_PLUS_STYLE,
};

let blame_palette = make_blame_palette(opt.blame_palette, opt.computed.is_light_mode);

let file_added_label = opt.file_added_label;
let file_copied_label = opt.file_copied_label;
let file_modified_label = opt.file_modified_label;
Expand Down Expand Up @@ -257,6 +262,9 @@ impl From<cli::Opt> for Config {
background_color_extends_to_terminal_width: opt
.computed
.background_color_extends_to_terminal_width,
blame_format: opt.blame_format,
blame_palette,
blame_timestamp_format: opt.blame_timestamp_format,
commit_style,
color_only: opt.color_only,
commit_regex,
Expand Down Expand Up @@ -603,6 +611,23 @@ fn make_commit_file_hunk_header_styles(opt: &cli::Opt) -> (Style, Style, Style,
)
}

fn make_blame_palette(blame_palette: Option<String>, is_light_mode: bool) -> Vec<String> {
match (blame_palette, is_light_mode) {
(Some(string), _) => string
.split_whitespace()
.map(|s| s.to_owned())
.collect::<Vec<String>>(),
(None, true) => color::LIGHT_THEME_BLAME_PALETTE
.iter()
.map(|s| s.to_string())
.collect::<Vec<String>>(),
(None, false) => color::DARK_THEME_BLAME_PALETTE
.iter()
.map(|s| s.to_string())
.collect::<Vec<String>>(),
}
}

/// Did the user supply `option` on the command line?
pub fn user_supplied_option(option: &str, arg_matches: &clap::ArgMatches) -> bool {
arg_matches.occurrences_of(option) > 0
Expand Down
5 changes: 5 additions & 0 deletions src/delta.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::io::BufRead;
use std::io::Write;

Expand All @@ -21,6 +22,7 @@ pub enum State {
HunkPlus(Option<String>), // In hunk; added line (raw_line)
SubmoduleLog, // In a submodule section, with gitconfig diff.submodule = log
SubmoduleShort(String), // In a submodule section, with gitconfig diff.submodule = short
Blame(String, Option<String>), // In a line of `git blame` output (commit, repeat_blame_line).
Unknown,
// The following elements are created when a line is wrapped to display it:
HunkZeroWrapped, // Wrapped unchanged line
Expand Down Expand Up @@ -67,6 +69,7 @@ pub struct StateMachine<'a> {
// avoid emitting the file meta header line twice (#245).
pub current_file_pair: Option<(String, String)>,
pub handled_file_meta_header_line_file_pair: Option<(String, String)>,
pub blame_commit_colors: HashMap<String, String>,
}

pub fn delta<I>(lines: ByteLines<I>, writer: &mut dyn Write, config: &Config) -> std::io::Result<()>
Expand All @@ -92,6 +95,7 @@ impl<'a> StateMachine<'a> {
handled_file_meta_header_line_file_pair: None,
painter: Painter::new(writer, config),
config,
blame_commit_colors: HashMap::new(),
}
}

Expand All @@ -116,6 +120,7 @@ impl<'a> StateMachine<'a> {
|| self.handle_submodule_log_line()?
|| self.handle_submodule_short_line()?
|| self.handle_hunk_line()?
|| self.handle_blame_line()?
|| self.should_skip_line()
|| self.emit_line_unchanged()?;
}
Expand Down
Loading

0 comments on commit 6719cf8

Please sign in to comment.