@@ -9,9 +9,10 @@ use std::net::SocketAddr;
99use tokio:: io:: { stdin, stdout} ;
1010use tracing_appender:: rolling:: { RollingFileAppender , Rotation } ;
1111use tracing_subscriber:: { self , EnvFilter , layer:: SubscriberExt , util:: SubscriberInitExt } ;
12+ use regex:: Regex ;
1213
1314#[ derive( Parser ) ]
14- #[ command( author, version = "0.1 .0" , about, long_about = None ) ]
15+ #[ command( author, version = "0.2 .0" , about, long_about = None ) ]
1516#[ command( propagate_version = true ) ]
1617#[ command( disable_version_flag = true ) ]
1718struct Cli {
@@ -70,6 +71,10 @@ enum Commands {
7071 /// Output file path (if not specified, results will be printed to stdout)
7172 #[ arg( long) ]
7273 output : Option < String > ,
74+
75+ /// Summarize output by stripping LICENSE and VERSION sections (TL;DR mode)
76+ #[ arg( long) ]
77+ tldr : bool ,
7378
7479 /// Enable debug logging
7580 #[ arg( short, long) ]
@@ -84,16 +89,17 @@ async fn main() -> Result<()> {
8489 match cli. command {
8590 Commands :: Stdio { debug } => run_stdio_server ( debug) . await ,
8691 Commands :: Http { address, debug } => run_http_server ( address, debug) . await ,
87- Commands :: Test {
88- tool,
89- crate_name,
90- item_path,
91- query,
92- version,
92+ Commands :: Test {
93+ tool,
94+ crate_name,
95+ item_path,
96+ query,
97+ version,
9398 limit,
9499 format,
95100 output,
96- debug
101+ tldr,
102+ debug
97103 } => run_test_tool ( TestToolConfig {
98104 tool,
99105 crate_name,
@@ -103,6 +109,7 @@ async fn main() -> Result<()> {
103109 limit,
104110 format,
105111 output,
112+ tldr,
106113 debug
107114 } ) . await ,
108115 }
@@ -163,6 +170,41 @@ async fn run_http_server(address: String, debug: bool) -> Result<()> {
163170 Ok ( ( ) )
164171}
165172
173+ // --- TLDR Helper Function ---
174+ fn apply_tldr ( input : & str ) -> String {
175+ // Remove LICENSE and VERSION(S) sections by skipping lines between those headings and the next heading or EOF.
176+ let mut output = Vec :: new ( ) ;
177+ let mut skip = false ;
178+
179+ let license_re = Regex :: new ( r"(?i)^\s*#+\s*license\b" ) . unwrap ( ) ;
180+ let version_re = Regex :: new ( r"(?i)^\s*#+\s*version(s)?\b" ) . unwrap ( ) ;
181+ let heading_re = Regex :: new ( r"^\s*#+\s*\S+" ) . unwrap ( ) ;
182+
183+ let mut just_skipped_section = false ;
184+ for line in input. lines ( ) {
185+ // Start skipping if we hit a LICENSE or VERSION(S) heading
186+ if !skip && ( license_re. is_match ( line) || version_re. is_match ( line) ) {
187+ skip = true ;
188+ just_skipped_section = true ;
189+ continue ; // skip the heading line itself
190+ }
191+ // If we just skipped a section heading, also skip blank lines and lines containing only "license" or "versions"
192+ if just_skipped_section && ( line. trim ( ) . is_empty ( ) || line. trim ( ) . eq_ignore_ascii_case ( "license" ) || line. trim ( ) . eq_ignore_ascii_case ( "versions" ) || line. trim ( ) . eq_ignore_ascii_case ( "version" ) ) {
193+ continue ;
194+ }
195+ // Stop skipping at the next heading (but do not skip the heading itself)
196+ if skip && heading_re. is_match ( line) {
197+ skip = false ;
198+ just_skipped_section = false ;
199+ }
200+ if !skip {
201+ output. push ( line) ;
202+ }
203+ }
204+ // If the section to skip is at the end, skip will remain true and those lines will be omitted.
205+ output. join ( "\n " )
206+ }
207+
166208/// Configuration for the test tool
167209struct TestToolConfig {
168210 tool : String ,
@@ -173,6 +215,7 @@ struct TestToolConfig {
173215 limit : Option < u32 > ,
174216 format : Option < String > ,
175217 output : Option < String > ,
218+ tldr : bool ,
176219 debug : bool ,
177220}
178221
@@ -187,6 +230,7 @@ async fn run_test_tool(config: TestToolConfig) -> Result<()> {
187230 limit,
188231 format,
189232 output,
233+ tldr,
190234 debug,
191235 } = config;
192236 // Print help information if the tool is "help"
@@ -210,6 +254,7 @@ async fn run_test_tool(config: TestToolConfig) -> Result<()> {
210254 println ! ( "\n Output options:" ) ;
211255 println ! ( " --format - Output format: markdown (default), text, json" ) ;
212256 println ! ( " --output - Write output to a file instead of stdout" ) ;
257+ println ! ( " --tldr - Summarize output by stripping LICENSE and VERSION sections" ) ;
213258 return Ok ( ( ) ) ;
214259 }
215260
@@ -289,7 +334,13 @@ async fn run_test_tool(config: TestToolConfig) -> Result<()> {
289334 if !result. is_empty ( ) {
290335 for content in result {
291336 if let Content :: Text ( text) = content {
292- let content_str = text. text ;
337+ let mut content_str = text. text ;
338+
339+ // TL;DR processing: strip LICENSE and VERSION(S) sections if --tldr is set
340+ if tldr {
341+ content_str = apply_tldr ( & content_str) ;
342+ }
343+
293344 let formatted_output = match format. as_str ( ) {
294345 "json" => {
295346 // For search_crates, which may return JSON content
@@ -321,7 +372,7 @@ async fn run_test_tool(config: TestToolConfig) -> Result<()> {
321372 let description = crate_info. get ( "description" ) . and_then ( |v| v. as_str ( ) ) . unwrap_or ( "No description" ) ;
322373 let downloads = crate_info. get ( "downloads" ) . and_then ( |v| v. as_u64 ( ) ) . unwrap_or ( 0 ) ;
323374
324- text_output. push_str ( & format ! ( "{}. {} - {} (Downloads: {})\n " ,
375+ text_output. push_str ( & format ! ( "{}. {} - {} (Downloads: {})\n " ,
325376 i + 1 , name, description, downloads) ) ;
326377 }
327378 text_output
@@ -384,4 +435,45 @@ async fn run_test_tool(config: TestToolConfig) -> Result<()> {
384435 }
385436
386437 Ok ( ( ) )
387- }
438+ }
439+ #[ cfg( test) ]
440+ mod tldr_tests {
441+ use super :: apply_tldr;
442+
443+ #[ test]
444+ fn test_apply_tldr_removes_license_and_versions ( ) {
445+ let input = r#"
446+ # Versions
447+ This is version info.
448+
449+ # LICENSE
450+ MIT License text.
451+
452+ # Usage
453+ Some real documentation here.
454+
455+ # Another Section
456+ More docs.
457+ "# ;
458+ let output = apply_tldr ( input) ;
459+ assert ! ( !output. to_lowercase( ) . contains( "license" ) ) ;
460+ assert ! ( !output. to_lowercase( ) . contains( "version" ) ) ;
461+ assert ! ( output. contains( "Usage" ) ) ;
462+ assert ! ( output. contains( "Another Section" ) ) ;
463+ assert ! ( output. contains( "Some real documentation here." ) ) ;
464+ // Debug print for failure analysis
465+ if output. to_lowercase ( ) . contains ( "license" ) {
466+ println ! ( "DEBUG OUTPUT:\n {}" , output) ;
467+ }
468+ }
469+
470+ #[ test]
471+ fn test_apply_tldr_handles_no_license_or_versions ( ) {
472+ let input = r#"
473+ # Usage
474+ Some real documentation here.
475+ "# ;
476+ let output = apply_tldr ( input) ;
477+ assert_eq ! ( output. trim( ) , input. trim( ) ) ;
478+ }
479+ }
0 commit comments