Skip to content

Commit 3e11c0c

Browse files
committed
nh search: fix links and add github link
when you run a nh search <packagename> command, the output previously looked like: ``` $ nh search fluffychat Querying search.nixos.org, with channel nixos-unstable... warning: Nix search path entry '/home/greg/.nix-defexpr/channels' does not exist, ignoring error: file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I) Took 120ms Most relevant results at the end fluffychat-web (2.0.0) Chat with your friends (matrix client) Homepage: https://fluffychat.im/ Defined at: pkgs/by-name/fl/fluffychat/package.nix fluffychat (2.0.0) Chat with your friends (matrix client) Homepage: https://fluffychat.im/ Defined at: pkgs/by-name/fl/fluffychat/package.nix ``` And the "Defined at" links were broken on nix flake systems - they pointed at a nonexistant file. This commit fixes that broken link and also adds an additional link to the file on the nixpkgs github repository: ``` $ cargo run -- search fluffychat Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.10s Running `target/debug/nh search fluffychat` Querying search.nixos.org, with channel nixos-unstable... Took 160ms Most relevant results at the end fluffychat-web (2.2.0) Chat with your friends (matrix client) Homepage: https://fluffychat.im/ Defined at: pkgs/by-name/fl/fluffychat/package.nix Github link: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/fl/fluffychat/package.nix fluffychat (2.2.0) Chat with your friends (matrix client) Homepage: https://fluffychat.im/ Defined at: pkgs/by-name/fl/fluffychat/package.nix Github link: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/fl/fluffychat/package.nix ```
1 parent 47374db commit 3e11c0c

File tree

2 files changed

+84
-39
lines changed

2 files changed

+84
-39
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ functionality, under the "Removed" section.
4646
Manager and Darwin. The logs were previously always visible.
4747
- The flag can be set globally via the `NH_SHOW_ACTIVATION_LOGS` environment
4848
variable.
49+
- `nh search` displays a link to the `package.nix` file on the nixpkgs Github,
50+
and also now creates unbroken links on nix flakes systems.
4951

5052
### Fixed
5153

src/search.rs

Lines changed: 82 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use tracing::{debug, trace, warn};
1515
use yansi::{Color, Paint};
1616

1717
use crate::{Result, interface};
18+
const GITHUB_NIXPKGS_URL: &str =
19+
"https://github.com/NixOS/nixpkgs/blob/nixos-unstable";
1820

1921
// List of deprecated NixOS versions
2022
// Add new versions as they become deprecated.
@@ -44,12 +46,23 @@ struct SearchResult {
4446
package_position: Option<String>,
4547
}
4648

47-
macro_rules! print_hyperlink {
48-
($text:expr, $link:expr) => {
49-
print!("\x1b]8;;{}\x07", $link);
50-
print!("{}", Paint::new($text).underline());
49+
// Cache the hyperlink support check result
50+
static HYPERLINKS_SUPPORTED: OnceLock<bool> = OnceLock::new();
51+
52+
// Prints an underlined link in the terminal, where the visible text may be
53+
// different from the link - or just print the text if hyperlinks aren't
54+
// supported
55+
fn print_hyperlink(text: &str, link: &str) {
56+
let hyperlinks =
57+
*HYPERLINKS_SUPPORTED.get_or_init(supports_hyperlinks::supports_hyperlinks);
58+
59+
if hyperlinks {
60+
print!("\x1b]8;;{link}\x07");
61+
print!("{}", Paint::new(text).underline());
5162
println!("\x1b]8;;\x07");
52-
};
63+
} else {
64+
println!("{text}");
65+
}
5366
}
5467

5568
#[derive(Debug, Serialize)]
@@ -77,11 +90,32 @@ impl SearchArgs {
7790
bail!("Channel {channel} is not supported!");
7891
}
7992

80-
let nixpkgs_path = std::thread::spawn(|| {
81-
std::process::Command::new("nix")
82-
.stderr(Stdio::inherit())
93+
// Map search channel to flake reference for flakes users
94+
let flake_ref = if channel == "nixos-unstable" {
95+
"github:NixOS/nixpkgs/nixos-unstable".to_string()
96+
} else if channel.starts_with("nixos-") {
97+
format!("github:NixOS/nixpkgs/{channel}")
98+
} else {
99+
"nixpkgs".to_string() // fallback to registry default
100+
};
101+
102+
let nixpkgs_path = std::thread::spawn(move || {
103+
// First try traditional <nixpkgs> for non-flakes users
104+
if let Ok(output) = std::process::Command::new("nix")
105+
.stderr(Stdio::null())
83106
.args(["eval", "-f", "<nixpkgs>", "path"])
84107
.output()
108+
{
109+
if output.status.success() {
110+
return Ok(output);
111+
}
112+
}
113+
114+
// Fallback: try flakes with matching channel
115+
std::process::Command::new("nix")
116+
.stderr(Stdio::null())
117+
.args(["eval", "--raw", &format!("{flake_ref}#path")])
118+
.output()
85119
});
86120

87121
let query_s = self.query.join(" ");
@@ -212,18 +246,26 @@ impl SearchArgs {
212246
return Ok(());
213247
}
214248

215-
let hyperlinks = supports_hyperlinks::supports_hyperlinks();
216-
debug!(?hyperlinks);
217-
218249
let nixpkgs_path_output = nixpkgs_path.join().map_err(|e| {
219250
color_eyre::eyre::eyre!("nixpkgs_path thread panicked: {e:?}")
220251
})?;
252+
debug!("{:?}", nixpkgs_path_output);
253+
254+
// Handle nixpkgs path gracefully - it might fail for flakes users or other
255+
// reasons
256+
let nixpkgs_path = nixpkgs_path_output
257+
.ok()
258+
.and_then(|output| {
259+
if output.status.success() {
260+
String::from_utf8(output.stdout).ok()
261+
} else {
262+
None
263+
}
264+
})
265+
.map(|s| s.trim().to_string())
266+
.unwrap_or_default();
221267

222-
let nixpkgs_path_output =
223-
nixpkgs_path_output.context("Evaluating the nixpkgs path location")?;
224-
225-
let nixpkgs_path = String::from_utf8(nixpkgs_path_output.stdout)
226-
.context("Converting nixpkgs_path to UTF-8")?;
268+
debug!("nixpkgs_path: {:?}", nixpkgs_path);
227269

228270
for elem in documents.iter().rev() {
229271
println!();
@@ -246,35 +288,36 @@ impl SearchArgs {
246288

247289
for url in &elem.package_homepage {
248290
print!(" Homepage: ");
249-
if hyperlinks {
250-
print_hyperlink!(url, url);
251-
} else {
252-
println!("{url}");
253-
}
291+
print_hyperlink(url, url);
254292
}
255293

256294
if self.platforms && !elem.package_platforms.is_empty() {
257295
println!(" Platforms: {}", elem.package_platforms.join(", "));
258296
}
259297

260-
if let Some(position) = &elem.package_position {
261-
let position = position
262-
.split(':')
263-
.next()
264-
.expect("Position should have at least one part");
265-
print!(" Defined at: ");
266-
if hyperlinks {
267-
let position_trimmed = position
268-
.split(':')
269-
.next()
270-
.expect("Removing line number from position");
271-
272-
print_hyperlink!(
273-
position,
274-
format!("file://{nixpkgs_path}/{position_trimmed}")
275-
);
276-
} else {
277-
println!("{position}");
298+
if let Some(package_position) = &elem.package_position {
299+
match package_position.split(':').next() {
300+
Some(position) => {
301+
// Position from search.nixos.org is already a relative path
302+
// like "pkgs/by-name/..."
303+
if !nixpkgs_path.is_empty() {
304+
print!(" Defined at: ");
305+
print_hyperlink(
306+
position,
307+
&format!("file://{nixpkgs_path}/{position}"),
308+
);
309+
310+
print!(" Github link: ");
311+
let url = format!("{GITHUB_NIXPKGS_URL}/{position}");
312+
print_hyperlink(&url, &url);
313+
}
314+
},
315+
None => {
316+
warn!(
317+
"Position should have at least one part; received \
318+
{package_position}"
319+
);
320+
},
278321
}
279322
}
280323
}

0 commit comments

Comments
 (0)