@@ -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 ;
@@ -1465,6 +1465,32 @@ impl DocPage {
1465
1465
fn name ( & self ) -> Option < & ' static str > {
1466
1466
Some ( self . path_str ( ) ?. rsplit_once ( '/' ) ?. 0 )
1467
1467
}
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
+ }
1468
1494
}
1469
1495
1470
1496
async fn doc (
@@ -1501,11 +1527,22 @@ async fn doc(
1501
1527
}
1502
1528
} ;
1503
1529
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
+ }
1509
1546
} ;
1510
1547
1511
1548
if path_only {
@@ -1522,7 +1559,7 @@ async fn doc(
1522
1559
} else {
1523
1560
writeln ! ( cfg. process. stderr( ) . lock( ) , "Opening docs in your browser" ) ?;
1524
1561
}
1525
- toolchain. open_docs ( & doc_path, None ) ?;
1562
+ toolchain. open_docs ( & doc_path, fragment ) ?;
1526
1563
Ok ( utils:: ExitCode ( 0 ) )
1527
1564
}
1528
1565
0 commit comments