Skip to content

Commit f4f71c1

Browse files
committed
Cache the Git remote URL to speed up rendering hyperlinks
This commit speeds up the rendering of hyperlinks by ~55x by caching the Git repo's remote URL instead of fetching it each time a hyperlink is rendered. Fixes dandavison#1939
1 parent ef3e1be commit f4f71c1

File tree

5 files changed

+46
-22
lines changed

5 files changed

+46
-22
lines changed

src/delta.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::config::delta_unreachable;
99
use crate::config::Config;
1010
use crate::config::GrepType;
1111
use crate::features;
12+
use crate::git_config::GitRemoteRepo;
1213
use crate::handlers::grep;
1314
use crate::handlers::hunk_header::{AmbiguousDiffMinusCounter, ParsedHunkHeader};
1415
use crate::handlers::{self, merge_conflict};
@@ -112,6 +113,7 @@ pub struct StateMachine<'a> {
112113
pub handled_diff_header_header_line_file_pair: Option<(String, String)>,
113114
pub blame_key_colors: HashMap<String, String>,
114115
pub minus_line_counter: AmbiguousDiffMinusCounter,
116+
pub git_remote_repo: Option<GitRemoteRepo>,
115117
}
116118

117119
pub fn delta<I>(lines: ByteLines<I>, writer: &mut dyn Write, config: &Config) -> std::io::Result<()>
@@ -140,6 +142,7 @@ impl<'a> StateMachine<'a> {
140142
config,
141143
blame_key_colors: HashMap::new(),
142144
minus_line_counter: AmbiguousDiffMinusCounter::not_needed(),
145+
git_remote_repo: features::hyperlinks::remote_from_config(&config.git_config()),
143146
}
144147
}
145148

@@ -248,7 +251,7 @@ impl<'a> StateMachine<'a> {
248251
writeln!(
249252
self.painter.writer,
250253
"{}",
251-
format_raw_line(&self.raw_line, self.config)
254+
format_raw_line(&self.raw_line, self.config, &self.git_remote_repo)
252255
)?;
253256
let handled_line = true;
254257
Ok(handled_line)
@@ -265,9 +268,13 @@ impl<'a> StateMachine<'a> {
265268

266269
/// If output is going to a tty, emit hyperlinks if requested.
267270
// Although raw output should basically be emitted unaltered, we do this.
268-
pub fn format_raw_line<'a>(line: &'a str, config: &Config) -> Cow<'a, str> {
271+
pub fn format_raw_line<'a>(
272+
line: &'a str,
273+
config: &Config,
274+
repo: &Option<GitRemoteRepo>,
275+
) -> Cow<'a, str> {
269276
if config.hyperlinks && io::stdout().is_terminal() {
270-
features::hyperlinks::format_commit_line_with_osc8_commit_hyperlink(line, config)
277+
features::hyperlinks::format_commit_line_with_osc8_commit_hyperlink(line, config, repo)
271278
} else {
272279
Cow::from(line)
273280
}

src/features/hyperlinks.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ pub fn make_feature() -> Vec<(String, OptionValueFunction)> {
2121

2222
#[cfg(test)]
2323
pub fn remote_from_config(_: &Option<&GitConfig>) -> Option<GitRemoteRepo> {
24-
Some(GitRemoteRepo::GitHub {
25-
slug: "dandavison/delta".to_string(),
26-
})
24+
GitRemoteRepo::for_testing()
2725
}
2826

2927
#[cfg(not(test))]
@@ -41,6 +39,7 @@ lazy_static! {
4139
pub fn format_commit_line_with_osc8_commit_hyperlink<'a>(
4240
line: &'a str,
4341
config: &Config,
42+
cached_repo: &Option<GitRemoteRepo>,
4443
) -> Cow<'a, str> {
4544
// Given matches in a line, m = matches[0] and pos = 0: store line[pos..m.start()] first, then
4645
// store the T(line[m.start()..m.end()]) match transformation, then set pos = m.end().
@@ -80,7 +79,7 @@ pub fn format_commit_line_with_osc8_commit_hyperlink<'a>(
8079
.with_input(line, &first_match, &mut matches);
8180
return Cow::from(result);
8281
}
83-
} else if let Some(repo) = remote_from_config(&config.git_config()) {
82+
} else if let Some(repo) = cached_repo {
8483
let mut matches = COMMIT_HASH_REGEX.find_iter(line);
8584
if let Some(first_match) = matches.next() {
8685
let result = HyperlinkCommits(|commit_hash| repo.format_commit_url(commit_hash))
@@ -144,35 +143,36 @@ pub mod tests {
144143

145144
#[test]
146145
fn test_formatted_hyperlinks() {
146+
let remote = GitRemoteRepo::for_testing();
147147
let config = make_config_from_args(&["--hyperlinks-commit-link-format", "HERE:{commit}"]);
148-
149148
let line = "001234abcdf";
150-
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config);
149+
150+
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config, &remote);
151151
assert_eq!(
152152
result,
153153
"\u{1b}]8;;HERE:001234abcdf\u{1b}\\001234abcdf\u{1b}]8;;\u{1b}\\",
154154
);
155155

156156
let line = "a2272718f0b398e48652ace17fca85c1962b3fc22"; // length: 41 > 40
157-
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config);
157+
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config, &remote);
158158
assert_eq!(result, "a2272718f0b398e48652ace17fca85c1962b3fc22",);
159159

160160
let line = "a2272718f0+b398e48652ace17f,ca85c1962b3fc2";
161-
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config);
161+
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config, &remote);
162162
assert_eq!(result, "\u{1b}]8;;HERE:a2272718f0\u{1b}\\a2272718f0\u{1b}]8;;\u{1b}\\+\u{1b}]8;;\
163163
HERE:b398e48652ace17f\u{1b}\\b398e48652ace17f\u{1b}]8;;\u{1b}\\,\u{1b}]8;;HERE:ca85c1962b3fc2\
164164
\u{1b}\\ca85c1962b3fc2\u{1b}]8;;\u{1b}\\");
165165

166166
let line = "This 01234abcdf Hash";
167-
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config);
167+
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config, &remote);
168168
assert_eq!(
169169
result,
170170
"This \u{1b}]8;;HERE:01234abcdf\u{1b}\\01234abcdf\u{1b}]8;;\u{1b}\\ Hash",
171171
);
172172

173173
let line =
174174
"Another 01234abcdf hash but also this one: dc623b084ad2dd14fe5d90189cacad5d49bfbfd3!";
175-
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config);
175+
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config, &remote);
176176
assert_eq!(
177177
result,
178178
"Another \u{1b}]8;;HERE:01234abcdf\u{1b}\\01234abcdf\u{1b}]8;;\u{1b}\\ hash but \
@@ -181,7 +181,7 @@ pub mod tests {
181181
);
182182

183183
let line = "01234abcdf 03043baf30 12abcdef0 12345678";
184-
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config);
184+
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config, &remote);
185185
assert_eq!(
186186
result,
187187
"\u{1b}]8;;HERE:01234abcdf\u{1b}\\01234abcdf\u{1b}]8;;\u{1b}\\ \u{1b}]8;;\
@@ -194,9 +194,10 @@ pub mod tests {
194194
fn test_hyperlinks_to_repo() {
195195
let mut config = make_config_from_args(&["--hyperlinks"]);
196196
config.git_config = GitConfig::for_testing();
197+
let remote = GitRemoteRepo::for_testing();
197198

198199
let line = "This a589ff9debaefdd delta commit";
199-
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config);
200+
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config, &remote);
200201
assert_eq!(
201202
result,
202203
"This \u{1b}]8;;https://github.com/dandavison/delta/commit/a589ff9debaefdd\u{1b}\
@@ -205,7 +206,7 @@ pub mod tests {
205206

206207
let line =
207208
"Another a589ff9debaefdd hash but also this one: c5696757c0827349a87daa95415656!";
208-
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config);
209+
let result = format_commit_line_with_osc8_commit_hyperlink(line, &config, &remote);
209210
assert_eq!(
210211
result,
211212
"Another \u{1b}]8;;https://github.com/dandavison/delta/commit/a589ff9debaefdd\

src/git_config/remote.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ impl GitRemoteRepo {
3131
}
3232
}
3333
}
34+
35+
#[cfg(test)]
36+
pub fn for_testing() -> Option<GitRemoteRepo> {
37+
Some(GitRemoteRepo::GitHub {
38+
slug: "dandavison/delta".to_string(),
39+
})
40+
}
3441
}
3542

3643
lazy_static! {

src/handlers/blame.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::delta::{self, State, StateMachine};
1212
use crate::fatal;
1313
use crate::format::{self, FormatStringSimple, Placeholder};
1414
use crate::format::{make_placeholder_regex, parse_line_number_format};
15+
use crate::git_config::GitRemoteRepo;
1516
use crate::paint::{self, BgShouldFill, StyleSectionSpecifier};
1617
use crate::style::Style;
1718
use crate::utils::process;
@@ -48,7 +49,7 @@ impl StateMachine<'_> {
4849
false,
4950
);
5051
let mut formatted_blame_metadata =
51-
format_blame_metadata(&format_data, &blame, self.config);
52+
format_blame_metadata(&format_data, &blame, self.config, &self.git_remote_repo);
5253
let key = formatted_blame_metadata.clone();
5354
let is_repeat = previous_key.as_deref() == Some(&key);
5455
if is_repeat {
@@ -262,6 +263,7 @@ pub fn format_blame_metadata(
262263
format_data: &[format::FormatStringPlaceholderData],
263264
blame: &BlameLine,
264265
config: &config::Config,
266+
repo: &Option<GitRemoteRepo>,
265267
) -> String {
266268
let mut s = String::new();
267269
let mut suffix = "";
@@ -279,7 +281,9 @@ pub fn format_blame_metadata(
279281
}))
280282
}
281283
Some(Placeholder::Str("author")) => Some(Cow::from(blame.author)),
282-
Some(Placeholder::Str("commit")) => Some(delta::format_raw_line(blame.commit, config)),
284+
Some(Placeholder::Str("commit")) => {
285+
Some(delta::format_raw_line(blame.commit, config, repo))
286+
}
283287
None => None,
284288
_ => unreachable!("Unexpected `git blame` input"),
285289
};
@@ -421,7 +425,8 @@ mod tests {
421425
let blame = make_blame_line_with_time("1996-12-19T16:39:57-08:00");
422426
let config = integration_test_utils::make_config_from_args(&[]);
423427
let regex = Regex::new(r"^\d+ years ago$").unwrap();
424-
let result = format_blame_metadata(&[format_data], &blame, &config);
428+
let remote: Option<GitRemoteRepo> = None;
429+
let result = format_blame_metadata(&[format_data], &blame, &config, &remote);
425430
assert!(regex.is_match(result.trim()));
426431
}
427432

@@ -432,7 +437,8 @@ mod tests {
432437
let config = integration_test_utils::make_config_from_args(&[
433438
"--blame-timestamp-output-format=%Y-%m-%d %H:%M",
434439
]);
435-
let result = format_blame_metadata(&[format_data], &blame, &config);
440+
let remote: Option<GitRemoteRepo> = None;
441+
let result = format_blame_metadata(&[format_data], &blame, &config, &remote);
436442
assert_eq!(result.trim(), "1996-12-19 16:39");
437443
}
438444

@@ -444,11 +450,12 @@ mod tests {
444450

445451
let format_data1 = make_format_data_with_placeholder("author");
446452
let blame1 = make_blame_line_with_author("E\u{301}dith Piaf");
447-
let result1 = format_blame_metadata(&[format_data1], &blame1, &config);
453+
let remote: Option<GitRemoteRepo> = None;
454+
let result1 = format_blame_metadata(&[format_data1], &blame1, &config, &remote);
448455

449456
let format_data2 = make_format_data_with_placeholder("author");
450457
let blame2 = make_blame_line_with_author("Edith Piaf");
451-
let result2 = format_blame_metadata(&[format_data2], &blame2, &config);
458+
let result2 = format_blame_metadata(&[format_data2], &blame2, &config, &remote);
452459

453460
assert_eq!(
454461
count_trailing_spaces(result1),

src/handlers/commit_meta.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ impl StateMachine<'_> {
3737
features::hyperlinks::format_commit_line_with_osc8_commit_hyperlink(
3838
&self.line,
3939
self.config,
40+
&self.git_remote_repo,
4041
),
4142
features::hyperlinks::format_commit_line_with_osc8_commit_hyperlink(
4243
&self.raw_line,
4344
self.config,
45+
&self.git_remote_repo,
4446
),
4547
)
4648
} else {

0 commit comments

Comments
 (0)