Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions manual/src/hyperlinks.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@ Commit hashes link to GitHub/GitLab/Bitbucket (use `hyperlinks-commit-link-forma

The links on line numbers (in grep output, as well as diffs) are particularly interesting: with a little bit of effort, they can be made to open your editor or IDE at the correct line.
Use `hyperlinks-file-link-format` to construct the correct URL for your system.
For VSCode and JetBrains IDEs this is easy, since they support their own special URL protocols. Here are examples:
For VSCode, Zed, and JetBrains IDEs this is easy, since they support their own special URL protocols. Here are examples:

```gitconfig
[delta]
hyperlinks = true
hyperlinks-file-link-format = "vscode://file/{path}:{line}"
hyperlinks-file-link-format = "vscode://file/{path}{:line}"
# hyperlinks-file-link-format = "zed://file/{path}{:line}"
# hyperlinks-file-link-format = "idea://open?file={path}&line={line}"
# hyperlinks-file-link-format = "pycharm://open?file={path}&line={line}"
```

Zed also supports its own URL protocol, and probably others.
Available placeholders: `{path}` (absolute file path), `{line}` (line number), `{:line}` (line number with leading colon), and `{host}` (hostname). The `{:line}` placeholder is useful to avoid trailing colons when no line number is present.

If your editor does not have its own URL protocol, then there are still many possibilities, although they may be more work.

Expand Down
4 changes: 2 additions & 2 deletions manual/src/tips-and-tricks/using-delta-with-vscode.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ To format file links for opening in VSCode from other terminal emulators, use th
```gitconfig
[delta]
hyperlinks = true
hyperlinks-file-link-format = "vscode://file/{path}:{line}"
hyperlinks-file-link-format = "vscode://file/{path}{:line}"
```

(To use VSCode Insiders, change that to `vscode-insiders://file/{path}:{line}`).
(To use VSCode Insiders, change that to `vscode-insiders://file/{path}{:line}`).

See [hyperlinks](../hyperlinks.md).
10 changes: 5 additions & 5 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,11 +434,11 @@ pub struct Opt {
)]
/// Format string for file hyperlinks (requires --hyperlinks).
///
/// Placeholders "{path}" and "{line}" will be replaced by the absolute file path and the line
/// number; "{host}" with the hostname delta is currently running on. The default is to create
/// a hyperlink containing a standard file URI with only the filename, which your terminal or
/// OS should handle. You can specify any scheme, such as "file-line://{path}:{line}" and
/// register an application to handle it. See
/// Placeholders "{path}", "{line}", and "{:line}" (with colon prefix) will be replaced by the
/// absolute file path and line number; "{host}" with the hostname delta is currently running
/// on. The default is to create a hyperlink containing a standard file URI with only the
/// filename, which your terminal or OS should handle. You can specify any scheme, such as
/// "vscode://file/{path}{:line}" and register an application to handle it. See
/// <https://dandavison.github.io/delta/hyperlinks.html> for details.
pub hyperlinks_file_link_format: String,

Expand Down
7 changes: 7 additions & 0 deletions src/features/hyperlinks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ where
if let Some(host) = &config.hostname {
url = url.replace("{host}", host)
}

if let Some(n) = line_number {
url = url.replace("{:line}", &format!(":{n}"))
} else {
url = url.replace("{:line}", "")
}

if let Some(n) = line_number {
url = url.replace("{line}", &format!("{n}"))
} else {
Expand Down
76 changes: 76 additions & 0 deletions src/handlers/hunk_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,82 @@ pub mod tests {
assert_eq!(result, "");
}

#[test]
fn test_paint_file_path_with_line_number_hyperlinks_with_colon_line_placeholder() {
use std::{iter::FromIterator, path::PathBuf};

use crate::utils;

// This test confirms that the {:line} placeholder expands to include the colon and line
// number (e.g. ":3") when a line number is present. This is useful for URL schemes like
// zed:// that treat a path ending with a colon as filename that includes a colon
let config = integration_test_utils::make_config_from_args(&[
"--features",
"hyperlinks",
"--hyperlinks-file-link-format",
"zed://file/{path}{:line}",
]);
let relative_path = PathBuf::from_iter(["some-dir", "some-file"]);

let result = paint_file_path_with_line_number(
Some(3),
&relative_path.to_string_lossy(),
&config.hunk_header_style,
&config.hunk_header_line_number_style,
&config.hunk_header_style_include_file_path,
&config.hunk_header_style_include_line_number,
":",
&config,
);

assert_eq!(
result,
format!(
"\u{1b}]8;;zed://file/{}:3\u{1b}\\\u{1b}[34m3\u{1b}[0m\u{1b}]8;;\u{1b}\\",
utils::path::fake_delta_cwd_for_tests()
.join(relative_path)
.to_string_lossy()
)
);
}

#[test]
fn test_paint_file_path_with_line_number_hyperlinks_colon_line_placeholder_without_line() {
use std::{iter::FromIterator, path::PathBuf};

use crate::utils;

// This test confirms that the {:line} placeholder expands to an empty string when no line
// number is present, avoiding a trailing colon in the URL.
let config = integration_test_utils::make_config_from_args(&[
"--features",
"hyperlinks",
"--hyperlinks-file-link-format",
"zed://file/{path}{:line}",
]);
let relative_path = PathBuf::from_iter(["some-dir", "some-file"]);

let result = paint_file_path_with_line_number(
None,
&relative_path.to_string_lossy(),
&config.hunk_header_style,
&config.hunk_header_line_number_style,
&config.hunk_header_style_include_file_path,
&config.hunk_header_style_include_line_number,
":",
&config,
);

let path = utils::path::fake_delta_cwd_for_tests()
.join(relative_path)
.to_string_lossy()
.to_string();
assert!(
!result.contains(&format!("{}:", path)),
"URL should not have trailing colon"
);
}

#[test]
fn test_paint_file_path_with_line_number_empty_navigate() {
let config = integration_test_utils::make_config_from_args(&[
Expand Down