summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Otto <th1000s@posteo.net>2022-01-04 21:58:39 +0100
committerThomas Otto <th1000s@posteo.net>2022-01-16 22:13:35 +0100
commita5c256f2e48c47a47f7a5ca5f131871b14efeb7f (patch)
treeecb8d7eebcf8f87377e76884f6b9fee9434c78e5
parentb693fdd6e4bff52596e124d1d2cc299cc53ada97 (diff)
Show blame line numbers via blame-separator-formatblame_line_numbers_before_rebase
Prefix and suffix of the format string are separator_style highlighted, format options are none, {n}, {n:block}, {n:every-N}.
-rw-r--r--src/cli.rs12
-rw-r--r--src/config.rs6
-rw-r--r--src/handlers/blame.rs111
-rw-r--r--src/options/set.rs2
4 files changed, 123 insertions, 8 deletions
diff --git a/src/cli.rs b/src/cli.rs
index dece275b..cc26d782 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -551,9 +551,15 @@ pub struct Opt {
/// Available placeholders are "{timestamp}", "{author}", and "{commit}".
pub blame_format: String,
- #[clap(long = "blame-separator", default_value = "│")]
- /// Separator between the commit metadata and code sections of a git blame line.
- pub blame_separator: String,
+ /// Separator between the commit metadata and code sections of a line of git blame output. Contains
+ /// the line number by default. Possible values are "none" to disable line numbers or a format
+ /// string. This may contain one "{n:}" placeholder and will display the line number on every line.
+ /// A type may be added after all other format specifiers and can be separated by '_':
+ /// If type is set to 'block' (e.g. "{n:^4_block}") the line number will only be shown when a new blame
+ /// block starts; or if it is set to 'every-N' the line will be show with every block and every
+ /// N-th (modulo) line.
+ #[clap(long = "blame-separator-format", default_value = "│{n:^4}│")]
+ pub blame_separator_format: String,
#[clap(long = "blame-separator-style")]
/// Style string for the separator between the commit metadata and code sections of a git blame line.
diff --git a/src/config.rs b/src/config.rs
index 75bc7488..baddd084 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -17,6 +17,8 @@ use crate::features::navigate;
use crate::features::side_by_side::{self, ansifill, LeftRight};
use crate::git_config::{GitConfig, GitConfigEntry};
use crate::handlers;
+use crate::handlers::blame::parse_blame_line_numbers;
+use crate::handlers::blame::BlameLineNumbers;
use crate::minusplus::MinusPlus;
use crate::paint::BgFillMethod;
use crate::parse_styles;
@@ -63,8 +65,8 @@ pub struct Config {
pub background_color_extends_to_terminal_width: bool,
pub blame_code_style: Option<Style>,
pub blame_format: String,
+ pub blame_separator_format: BlameLineNumbers,
pub blame_palette: Vec<String>,
- pub blame_separator: String,
pub blame_separator_style: Option<Style>,
pub blame_timestamp_format: String,
pub color_only: bool,
@@ -248,7 +250,7 @@ impl From<cli::Opt> for Config {
blame_format: opt.blame_format,
blame_code_style: styles.remove("blame-code-style"),
blame_palette,
- blame_separator: opt.blame_separator,
+ blame_separator_format: parse_blame_line_numbers(&opt.blame_separator_format),
blame_separator_style: styles.remove("blame-separator-style"),
blame_timestamp_format: opt.blame_timestamp_format,
commit_style: styles["commit-style"],
diff --git a/src/handlers/blame.rs b/src/handlers/blame.rs
index f48e8841..2c22d854 100644
--- a/src/handlers/blame.rs
+++ b/src/handlers/blame.rs
@@ -8,11 +8,22 @@ use crate::color;
use crate::config;
use crate::config::delta_unreachable;
use crate::delta::{self, State, StateMachine};
+use crate::fatal;
+use crate::format::FormatStringSimple;
use crate::format::{self, Placeholder};
+use crate::format::{make_placeholder_regex, parse_line_number_format};
use crate::paint::{self, BgShouldFill, StyleSectionSpecifier};
use crate::style::Style;
use crate::utils;
+#[derive(Clone, Debug)]
+pub enum BlameLineNumbers {
+ // "none" equals a fixed string with just a separator
+ On(FormatStringSimple),
+ PerBlock(FormatStringSimple),
+ Every(usize, FormatStringSimple),
+}
+
impl<'a> StateMachine<'a> {
/// If this is a line of git blame output then render it accordingly. If
/// this is the first blame line, then set the syntax-highlighter language
@@ -49,11 +60,19 @@ impl<'a> StateMachine<'a> {
let code_style = self.config.blame_code_style.unwrap_or(metadata_style);
let separator_style = self.config.blame_separator_style.unwrap_or(code_style);
+ let (nr_prefix, line_number, nr_suffix) = format_blame_line_number(
+ &self.config.blame_separator_format,
+ blame.line_number,
+ is_repeat,
+ );
+
write!(
self.painter.writer,
- "{}{}",
+ "{}{}{}{}",
metadata_style.paint(&formatted_blame_metadata),
- separator_style.paint(&self.config.blame_separator)
+ separator_style.paint(nr_prefix),
+ metadata_style.paint(&line_number),
+ separator_style.paint(nr_suffix),
)?;
// Emit syntax-highlighted code
@@ -232,6 +251,7 @@ pub fn parse_git_blame_line<'a>(line: &'a str, timestamp_format: &str) -> Option
}
lazy_static! {
+ // line numbers are set via `blame_line_number_suffix`
pub static ref BLAME_PLACEHOLDER_REGEX: Regex =
format::make_placeholder_regex(&["timestamp", "author", "commit"]);
}
@@ -272,6 +292,93 @@ pub fn format_blame_metadata(
s
}
+pub fn format_blame_line_number(
+ format: &BlameLineNumbers,
+ line_number: usize,
+ is_repeat: bool,
+) -> (&str, String, &str) {
+ let (format, empty) = match &format {
+ BlameLineNumbers::PerBlock(format) => (format, is_repeat),
+ BlameLineNumbers::Every(n, format) => (format, is_repeat && line_number % n != 0),
+ BlameLineNumbers::On(format) => (format, false),
+ };
+ let mut result = String::new();
+
+ // depends on defaults being set when parsing arguments
+ let line_number = if format.width.is_some() {
+ format::pad(
+ line_number,
+ format.width.unwrap(),
+ format.alignment_spec.unwrap(),
+ None,
+ )
+ } else {
+ String::new()
+ };
+
+ if empty {
+ for _ in 0..measure_text_width(&line_number) {
+ result.push(' ');
+ }
+ } else {
+ result.push_str(&line_number);
+ }
+
+ (format.prefix.as_str(), result, format.suffix.as_str())
+}
+
+pub fn parse_blame_line_numbers(arg: &str) -> BlameLineNumbers {
+ if arg == "none" {
+ return BlameLineNumbers::On(crate::format::FormatStringSimple::only_string("│"));
+ }
+
+ let regex = make_placeholder_regex(&["n"]);
+ let f = match parse_line_number_format(arg, &regex, false) {
+ v if v.len() > 1 => {
+ fatal("Too many format arguments numbers for blame-line-numbers".to_string())
+ }
+ mut v => v.pop().unwrap(),
+ };
+
+ let set_defaults = |mut format: crate::format::FormatStringSimple| {
+ format.width = format.width.or(Some(4));
+ format.alignment_spec = format.alignment_spec.or(Some(crate::format::Align::Center));
+
+ format
+ };
+
+ if f.placeholder.is_none() {
+ return BlameLineNumbers::On(crate::format::FormatStringSimple::only_string(
+ f.suffix.as_str(),
+ ));
+ }
+
+ match f.fmt_type.as_str() {
+ t if t.is_empty() || t == "every" => BlameLineNumbers::On(set_defaults(f.into_simple())),
+ t if t == "block" => BlameLineNumbers::PerBlock(set_defaults(f.into_simple())),
+ every_n if every_n.starts_with("every-") => {
+ let n = every_n["every-".len()..]
+ .parse::<usize>()
+ .unwrap_or_else(|err| {
+ fatal(format!(
+ "Invalid number for blame-line-numbers in every-N argument: {}",
+ err
+ ))
+ });
+
+ if n > 1 {
+ BlameLineNumbers::Every(n, set_defaults(f.into_simple()))
+ } else {
+ BlameLineNumbers::On(set_defaults(f.into_simple()))
+ }
+ }
+ t => fatal(format!(
+ "Invalid format type \"{}\" for blame-line-numbers",
+ t
+ )),
+ }
+}
+
#[cfg(test)]
mod tests {
use itertools::Itertools;
diff --git a/src/options/set.rs b/src/options/set.rs
index e82b9f39..0e21c226 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
@@ -128,8 +128,8 @@ pub fn set_options(
[
blame_code_style,
blame_format,
+ blame_separator_format,
blame_palette,
- blame_separator,
blame_separator_style,
blame_timestamp_format,
color_only,