Skip to content

Commit a1f70d7

Browse files
committed
feat(cli/rustup-mode): allow rustup doc with both a flag and a topic
1 parent 94b7422 commit a1f70d7

File tree

1 file changed

+44
-7
lines changed

1 file changed

+44
-7
lines changed

src/cli/rustup_mode.rs

Lines changed: 44 additions & 7 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;
@@ -1465,6 +1465,32 @@ impl DocPage {
14651465
fn name(&self) -> Option<&'static str> {
14661466
Some(self.path_str()?.rsplit_once('/')?.0)
14671467
}
1468+
1469+
fn resolve<'t>(&self, root: &Path, topic: &'t str) -> Option<(PathBuf, Option<&'t str>)> {
1470+
// Save the components in case the last one is used later with `parent_html`.
1471+
let components = topic.split("::").collect::<Vec<_>>();
1472+
1473+
// Use `.parent()` to chop off the default top-level `index.html`.
1474+
let mut base = root.join(Path::new(self.path()?).parent()?);
1475+
base.extend(&components);
1476+
let base_index_html = base.join("index.html");
1477+
1478+
if base_index_html.is_file() {
1479+
return Some((base_index_html, None));
1480+
}
1481+
1482+
let base_html = base.with_extension("html");
1483+
if base_html.is_file() {
1484+
return Some((base_html, None));
1485+
}
1486+
1487+
let parent_html = base.parent()?.with_extension("html");
1488+
if parent_html.is_file() {
1489+
return Some((parent_html, components.last().copied()));
1490+
}
1491+
1492+
None
1493+
}
14681494
}
14691495

14701496
async fn doc(
@@ -1501,11 +1527,22 @@ async fn doc(
15011527
}
15021528
};
15031529

1504-
let doc_path: Cow<'_, Path> = if let Some(topic) = topic {
1505-
topical_doc::local_path(&toolchain.doc_path("").unwrap(), topic)?.into()
1506-
} else {
1507-
topic = doc_page.name();
1508-
doc_page.path().unwrap_or(Path::new("index.html")).into()
1530+
let (doc_path, fragment): (Cow<'_, Path>, _) = match (topic, doc_page.name()) {
1531+
(Some(topic), Some(name)) => {
1532+
let (doc_path, fragment) = doc_page
1533+
.resolve(&toolchain.doc_path("")?, topic)
1534+
.context(format!("no document for {name} on {topic}"))?;
1535+
(doc_path.into(), fragment)
1536+
}
1537+
(Some(topic), None) => {
1538+
let doc_path = topical_doc::local_path(&toolchain.doc_path("").unwrap(), topic)?;
1539+
(doc_path.into(), None)
1540+
}
1541+
(None, name) => {
1542+
topic = name;
1543+
let doc_path = doc_page.path().unwrap_or(Path::new("index.html"));
1544+
(doc_path.into(), None)
1545+
}
15091546
};
15101547

15111548
if path_only {
@@ -1522,7 +1559,7 @@ async fn doc(
15221559
} else {
15231560
writeln!(cfg.process.stderr().lock(), "Opening docs in your browser")?;
15241561
}
1525-
toolchain.open_docs(&doc_path, None)?;
1562+
toolchain.open_docs(&doc_path, fragment)?;
15261563
Ok(utils::ExitCode(0))
15271564
}
15281565

0 commit comments

Comments
 (0)