11use scraper:: { Html , Selector } ;
22use std:: fs;
3- use std:: path:: Path ;
3+ use cargo:: core:: resolver:: features:: CliFeatures ;
4+ // use cargo::core::SourceId; // Removed unused import
5+ // use cargo::util::Filesystem; // Removed unused import
6+
7+ use cargo:: core:: Workspace ;
8+ use cargo:: ops:: { self , CompileOptions , DocOptions , Packages } ;
9+ use cargo:: util:: context:: GlobalContext ;
10+ use anyhow:: Error as AnyhowError ;
11+ // use std::process::Command; // Remove Command again
12+ use tempfile:: tempdir;
413use thiserror:: Error ;
514use walkdir:: WalkDir ;
615
@@ -10,10 +19,12 @@ pub enum DocLoaderError {
1019 Io ( #[ from] std:: io:: Error ) ,
1120 #[ error( "WalkDir Error: {0}" ) ]
1221 WalkDir ( #[ from] walkdir:: Error ) ,
13- // #[error("Failed to parse HTML for file: {0}")] // Commented out unused variant
14- // HtmlParsing(String), // Commented out unused variant
1522 #[ error( "CSS selector error: {0}" ) ]
16- Selector ( String ) , // Using String as SelectorErrorKind is not easily clonable/convertible
23+ Selector ( String ) ,
24+ #[ error( "Temporary directory creation failed: {0}" ) ]
25+ TempDirCreationFailed ( std:: io:: Error ) ,
26+ #[ error( "Cargo library error: {0}" ) ]
27+ CargoLib ( #[ from] AnyhowError ) , // Re-add CargoLib variant
1728}
1829
1930// Simple struct to hold document content, maybe add path later if needed
@@ -23,11 +34,60 @@ pub struct Document {
2334 pub content : String ,
2435}
2536
26- /// Loads and parses HTML documents from a given directory path.
37+ /// Generates documentation for a given crate in a temporary directory,
38+ /// then loads and parses the HTML documents.
2739/// Extracts text content from the main content area of rustdoc generated HTML.
28- pub fn load_documents ( docs_path : & str ) -> Result < Vec < Document > , DocLoaderError > {
40+ pub fn load_documents ( crate_name : & str , _crate_version : & str ) -> Result < Vec < Document > , DocLoaderError > { // Mark version as unused for now
2941 let mut documents = Vec :: new ( ) ;
30- let docs_path = Path :: new ( docs_path) ;
42+
43+ let temp_dir = tempdir ( ) . map_err ( DocLoaderError :: TempDirCreationFailed ) ?;
44+ let temp_dir_path = temp_dir. path ( ) ;
45+
46+ println ! (
47+ "Generating documentation for crate '{}' in temporary directory: {}" ,
48+ crate_name,
49+ temp_dir_path. display( )
50+ ) ;
51+
52+ // Execute `cargo doc` using std::process::Command
53+ // --- Use Cargo API ---
54+ let config = GlobalContext :: default ( ) ?;
55+ // config.shell().set_verbosity(Verbosity::Quiet); // Keep commented
56+
57+ let current_dir = std:: env:: current_dir ( ) ?;
58+ let mut ws = Workspace :: new ( & current_dir. join ( "Cargo.toml" ) , & config) ?; // Make ws mutable
59+ // Set target_dir directly on Workspace
60+ ws. set_target_dir ( cargo:: util:: Filesystem :: new ( temp_dir_path. to_path_buf ( ) ) ) ;
61+
62+ // Create CompileOptions, relying on ::new for BuildConfig
63+ let mut compile_opts = CompileOptions :: new ( & config, cargo:: core:: compiler:: CompileMode :: Doc { deps : false , json : false } ) ?;
64+ // Specify the package explicitly
65+ let package_spec = crate_name. replace ( '-' , "_" ) ; // Just use name (with underscores)
66+ compile_opts. cli_features = CliFeatures :: new_all ( false ) ; // Use new_all(false)
67+ compile_opts. spec = Packages :: Packages ( vec ! [ package_spec] ) ;
68+
69+ // Create DocOptions: Pass compile options
70+ let doc_opts = DocOptions {
71+ compile_opts,
72+ open_result : false , // Don't open in browser
73+ output_format : ops:: OutputFormat :: Html ,
74+ } ;
75+
76+ ops:: doc ( & ws, & doc_opts) . map_err ( DocLoaderError :: CargoLib ) ?; // Use ws
77+ // --- End Cargo API ---
78+ // Construct the path to the generated documentation within the temp directory
79+ // Cargo uses underscores in the directory path if the crate name has hyphens
80+ let crate_name_underscores = crate_name. replace ( '-' , "_" ) ;
81+ let docs_path = temp_dir_path. join ( "doc" ) . join ( & crate_name_underscores) ;
82+
83+ if !docs_path. exists ( ) || !docs_path. is_dir ( ) {
84+ return Err ( DocLoaderError :: CargoLib ( anyhow:: anyhow!(
85+ "Generated documentation not found at expected path: {}. Check crate name and cargo doc output." ,
86+ docs_path. display( )
87+ ) ) ) ;
88+ }
89+ println ! ( "Generated documentation path: {}" , docs_path. display( ) ) ;
90+
3191
3292 // Define the CSS selector for the main content area in rustdoc HTML
3393 // This might need adjustment based on the exact rustdoc version/theme
@@ -39,7 +99,7 @@ pub fn load_documents(docs_path: &str) -> Result<Vec<Document>, DocLoaderError>
3999 for entry in WalkDir :: new ( docs_path)
40100 . into_iter ( )
41101 . filter_map ( Result :: ok) // Ignore errors during iteration for now
42- . filter ( |e| !e. file_type ( ) . is_dir ( ) && e. path ( ) . extension ( ) . map_or ( false , |ext| ext == "html" ) )
102+ . filter ( |e| !e. file_type ( ) . is_dir ( ) && e. path ( ) . extension ( ) . is_some_and ( |ext| ext == "html" ) )
43103 {
44104 let path = entry. path ( ) ;
45105 let path_str = path. to_string_lossy ( ) . to_string ( ) ;
0 commit comments