Skip to content

Commit 3b14eb5

Browse files
committed
feat(cli/rustup-mode): allow rustup doc with both a flag and a topic
1 parent a26a881 commit 3b14eb5

File tree

1 file changed

+41
-10
lines changed

1 file changed

+41
-10
lines changed

src/cli/rustup_mode.rs

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
66
use std::process::ExitStatus;
77
use std::str::FromStr;
88

9-
use anyhow::{anyhow, Error, Result};
9+
use anyhow::{anyhow, Context, Error, Result};
1010
use clap::{builder::PossibleValue, Args, CommandFactory, Parser, Subcommand, ValueEnum};
1111
use clap_complete::Shell;
1212
use itertools::Itertools;
@@ -1471,6 +1471,29 @@ impl DocPage {
14711471
fn name(&self) -> Option<&'static str> {
14721472
Some(self.path_str()?.rsplit_once('/')?.0)
14731473
}
1474+
1475+
fn resolve<'t>(&self, root: &Path, topic: &'t str) -> Option<(PathBuf, Option<&'t str>)> {
1476+
// Use `.parent()` to chop off the default top-level `index.html`.
1477+
let mut base = root.join(Path::new(self.path()?).parent()?);
1478+
base.extend(topic.split("::"));
1479+
let base_index_html = base.join("index.html");
1480+
1481+
if base_index_html.is_file() {
1482+
return Some((base_index_html, None));
1483+
}
1484+
1485+
let base_html = base.with_extension("html");
1486+
if base_html.is_file() {
1487+
return Some((base_html, None));
1488+
}
1489+
1490+
let parent_html = base.parent()?.with_extension("html");
1491+
if parent_html.is_file() {
1492+
return Some((parent_html, topic.rsplit_once("::").map(|(_, s)| s)));
1493+
}
1494+
1495+
None
1496+
}
14741497
}
14751498

14761499
async fn doc(
@@ -1507,14 +1530,22 @@ async fn doc(
15071530
}
15081531
};
15091532

1510-
let doc_path = if let Some(topic) = topic {
1511-
Cow::Owned(topical_doc::local_path(
1512-
&toolchain.doc_path("").unwrap(),
1513-
topic,
1514-
)?)
1515-
} else {
1516-
topic = doc_page.name();
1517-
Cow::Borrowed(doc_page.path().unwrap_or(Path::new("index.html")))
1533+
let (doc_path, fragment) = match (topic, doc_page.name()) {
1534+
(Some(topic), Some(name)) => {
1535+
let (doc_path, fragment) = doc_page
1536+
.resolve(&toolchain.doc_path("")?, topic)
1537+
.context(format!("no document for {name} on {topic}"))?;
1538+
(Cow::Owned(doc_path), fragment)
1539+
}
1540+
(Some(topic), None) => {
1541+
let doc_path = topical_doc::local_path(&toolchain.doc_path("").unwrap(), topic)?;
1542+
(Cow::Owned(doc_path), None)
1543+
}
1544+
(None, name) => {
1545+
topic = name;
1546+
let doc_path = doc_page.path().unwrap_or(Path::new("index.html"));
1547+
(Cow::Borrowed(doc_path), None)
1548+
}
15181549
};
15191550

15201551
if path_only {
@@ -1531,7 +1562,7 @@ async fn doc(
15311562
} else {
15321563
writeln!(cfg.process.stderr().lock(), "Opening docs in your browser")?;
15331564
}
1534-
toolchain.open_docs(&doc_path, None)?;
1565+
toolchain.open_docs(&doc_path, fragment)?;
15351566
Ok(utils::ExitCode(0))
15361567
}
15371568

0 commit comments

Comments
 (0)