summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2020-12-29 06:53:43 -0500
committerGitHub <noreply@github.com>2020-12-29 06:53:43 -0500
commitb8b968071698d74c0f644a4a169b73b0cf1445f1 (patch)
treef944017bcbb7cd27003bbdb7e2298af657c5fa54
parent703ce650756db5b378c67eb080e979e30ae1477e (diff)
Hyperlink file and line number (#479)
Hyperlinks seem to be rendering with just the file path underlined, at least in iTerm2, whereas the intention was for the file and line-number to be rendered jointly (both underlined) as a hyperlink. The link structure is ␛]8;;file-line-column:///Users/dan/src/delta/src/hunk_header.rs:114␛\␛[38;5;1msrc/hunk_header.rs␛[0m:␛[38;5;4m114␛[0m␛]8;;␛\:
-rw-r--r--src/delta.rs10
-rw-r--r--src/hunk_header.rs148
-rw-r--r--src/tests/test_example_diffs.rs8
3 files changed, 90 insertions, 76 deletions
diff --git a/src/delta.rs b/src/delta.rs
index f72302e4..81871068 100644
--- a/src/delta.rs
+++ b/src/delta.rs
@@ -350,7 +350,7 @@ impl<'a> StateMachine<'a> {
self.painter.set_highlighter();
self.painter.emit()?;
- let (raw_code_fragment, line_numbers) = parse::parse_hunk_header(&self.line);
+ let (code_fragment, line_numbers) = parse::parse_hunk_header(&self.line);
if self.config.line_numbers {
self.painter
.line_numbers_data
@@ -367,8 +367,14 @@ impl<'a> StateMachine<'a> {
} else if self.config.hunk_header_style.is_omitted {
writeln!(self.painter.writer)?;
} else {
+ // Add a blank line below the hunk-header-line for readability, unless
+ // color_only mode is active.
+ if !self.config.color_only {
+ writeln!(self.painter.writer)?;
+ }
+
hunk_header::write_hunk_header(
- &raw_code_fragment,
+ &code_fragment,
&line_numbers,
&mut self.painter,
&self.line,
diff --git a/src/hunk_header.rs b/src/hunk_header.rs
index b44a6330..7b7af31f 100644
--- a/src/hunk_header.rs
+++ b/src/hunk_header.rs
@@ -1,4 +1,24 @@
-use std::borrow::Cow;
+//! A module for constructing and writing the hunk header.
+//!
+//! The structure of the hunk header output by delta is
+//! ```
+//! (file):(line-number): (code-fragment)
+//! ```
+//!
+//! The code fragment and line number derive from a line of git/diff output that looks like
+//! ```
+//! @@ -119,12 +119,7 @@ fn write_to_output_buffer(
+//! ```
+//!
+//! Whether or not file and line-number are included is controlled by the presence of the special
+//! style attributes 'file' and 'line-number' in the hunk-header-style string. For example, delta
+//! might output the above hunk header as
+//! ```
+//! ───────────────────────────────────────────────────┐
+//! src/hunk_header.rs:119: fn write_to_output_buffer( │
+//! ───────────────────────────────────────────────────┘
+//! ```
+
use std::fmt::Write as FmtWrite;
use crate::config::Config;
@@ -31,7 +51,7 @@ pub fn write_hunk_header_raw(
}
pub fn write_hunk_header(
- raw_code_fragment: &str,
+ code_fragment: &str,
line_numbers: &[(usize, usize)],
painter: &mut Painter,
line: &str,
@@ -42,42 +62,78 @@ pub fn write_hunk_header(
draw::get_draw_function(config.hunk_header_style.decoration_style);
let line = if config.color_only {
format!(" {}", &line)
- } else if !raw_code_fragment.is_empty() {
- format!("{} ", raw_code_fragment)
+ } else if !code_fragment.is_empty() {
+ format!("{} ", code_fragment)
} else {
"".to_string()
};
- // Add a blank line below the hunk-header-line for readability, unless
- // color_only mode is active.
- if !config.color_only {
- writeln!(painter.writer)?;
+ let file_with_line_number = get_painted_file_with_line_number(line_numbers, plus_file, config);
+
+ if !line.is_empty() || !file_with_line_number.is_empty() {
+ write_to_output_buffer(&file_with_line_number, line, painter, config);
+ draw_fn(
+ painter.writer,
+ &painter.output_buffer,
+ &painter.output_buffer,
+ &config.decorations_width,
+ config.null_style,
+ decoration_ansi_term_style,
+ )?;
+ painter.output_buffer.clear();
}
- let mut have_hunk_header = false;
+ Ok(())
+}
+
+fn get_painted_file_with_line_number(
+ line_numbers: &[(usize, usize)],
+ plus_file: &str,
+ config: &Config,
+) -> String {
+ let mut file_with_line_number = Vec::new();
+ let plus_line_number = line_numbers[line_numbers.len() - 1].0;
if config.hunk_header_style_include_file_path {
- let _ = write!(
- &mut painter.output_buffer,
- "{}",
- config.file_style.paint(plus_file),
- );
- have_hunk_header = true;
+ file_with_line_number.push(config.file_style.paint(plus_file))
};
if !config.line_numbers
&& config.hunk_header_style_include_line_number
&& !config.hunk_header_style.is_raw
&& !config.color_only
{
- if have_hunk_header {
- let _ = write!(&mut painter.output_buffer, ":");
+ if !file_with_line_number.is_empty() {
+ file_with_line_number.push(ansi_term::ANSIString::from(":"));
}
- _write_line_number(&line_numbers, painter, plus_file, config)?;
- have_hunk_header = true;
+ if let Some(style) = config.hunk_header_style.decoration_ansi_term_style() {
+ file_with_line_number.push(style.paint(format!("{}", plus_line_number)))
+ } else {
+ file_with_line_number.push(ansi_term::ANSIString::from(format!("{}", plus_line_number)))
+ }
+ }
+ let file_with_line_number = ansi_term::ANSIStrings(&file_with_line_number).to_string();
+ if config.hyperlinks {
+ features::hyperlinks::format_osc8_file_hyperlink(
+ plus_file,
+ Some(plus_line_number),
+ &file_with_line_number,
+ config,
+ )
+ .into()
+ } else {
+ file_with_line_number
+ }
+}
+
+fn write_to_output_buffer(
+ file_with_line_number: &str,
+ line: String,
+ painter: &mut Painter,
+ config: &Config,
+) {
+ if !file_with_line_number.is_empty() {
+ let _ = write!(&mut painter.output_buffer, "{}: ", file_with_line_number);
}
if !line.is_empty() {
- if have_hunk_header {
- let _ = write!(&mut painter.output_buffer, ": ");
- }
let lines = vec![(line, delta::State::HunkHeader)];
let syntax_style_sections = Painter::get_syntax_style_sections_for_lines(
&lines,
@@ -97,53 +153,5 @@ pub fn write_hunk_header(
Some(false),
);
painter.output_buffer.pop(); // trim newline
- have_hunk_header = true;
- } else if have_hunk_header {
- let _ = write!(&mut painter.output_buffer, " ");
}
- if have_hunk_header {
- draw_fn(
- painter.writer,
- &painter.output_buffer,
- &painter.output_buffer,
- &config.decorations_width,
- config.null_style,
- decoration_ansi_term_style,
- )?;
- painter.output_buffer.clear();
- }
-
- Ok(())
-}
-
-fn _write_line_number(
- line_numbers: &[(usize, usize)],
- painter: &mut Painter,
- plus_file: &str,
- config: &Config,
-) -> std::io::Result<()> {
- let plus_line_number = line_numbers[line_numbers.len() - 1].0;
- let formatted_plus_line_number = if config.hyperlinks {
- features::hyperlinks::format_osc8_file_hyperlink(
- plus_file,
- Some(plus_line_number),
- &format!("{}", plus_line_number),
- config,
- )
- } else {
- Cow::from(format!("{}", plus_line_number))
- };
- match config.hunk_header_style.decoration_ansi_term_style() {
- Some(style) => {
- let _ = write!(
- &mut painter.output_buffer,
- "{}",
- style.paint(formatted_plus_line_number)
- );
- }
- None => {
- let _ = write!(&mut painter.output_buffer, "{}", formatted_plus_line_number);
- }
- }
- Ok(())
}
diff --git a/src/tests/test_example_diffs.rs b/src/tests/test_example_diffs.rs
index 402a88a5..b3a8bf36 100644
--- a/src/tests/test_example_diffs.rs
+++ b/src/tests/test_example_diffs.rs
@@ -1043,13 +1043,13 @@ src/align.rs:71: impl<'a> Alignment<'a> { │
]);
let output = integration_test_utils::run_delta(GIT_DIFF_SINGLE_HUNK_NO_FRAG, &config);
- ansi_test_utils::assert_line_has_style(&output, 5, "src/delta.rs:1 ", "yellow", &config);
+ ansi_test_utils::assert_line_has_style(&output, 5, "src/delta.rs:1: ", "yellow", &config);
let output = strip_ansi_codes(&output);
assert!(output.contains(
"
-───────────────┐
-src/delta.rs:1 │
-───────────────┘
+────────────────┐
+src/delta.rs:1: │
+────────────────┘
"
));
}