@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
6
6
use std:: process:: ExitStatus ;
7
7
use std:: str:: FromStr ;
8
8
9
- use anyhow:: { anyhow, Error , Result } ;
9
+ use anyhow:: { anyhow, Context , Error , Result } ;
10
10
use clap:: { builder:: PossibleValue , Args , CommandFactory , Parser , Subcommand , ValueEnum } ;
11
11
use clap_complete:: Shell ;
12
12
use itertools:: Itertools ;
@@ -1471,6 +1471,29 @@ impl DocPage {
1471
1471
fn name ( & self ) -> Option < & ' static str > {
1472
1472
Some ( self . path_str ( ) ?. rsplit_once ( '/' ) ?. 0 )
1473
1473
}
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
+ }
1474
1497
}
1475
1498
1476
1499
async fn doc (
@@ -1507,14 +1530,22 @@ async fn doc(
1507
1530
}
1508
1531
} ;
1509
1532
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
+ }
1518
1549
} ;
1519
1550
1520
1551
if path_only {
@@ -1531,7 +1562,7 @@ async fn doc(
1531
1562
} else {
1532
1563
writeln ! ( cfg. process. stderr( ) . lock( ) , "Opening docs in your browser" ) ?;
1533
1564
}
1534
- toolchain. open_docs ( & doc_path, None ) ?;
1565
+ toolchain. open_docs ( & doc_path, fragment ) ?;
1535
1566
Ok ( utils:: ExitCode ( 0 ) )
1536
1567
}
1537
1568
0 commit comments