doc.rs (13337B)
1 use crate::chatops::{ChatCommand, ChatOpError, ChatOpResult, CommandContext}; 2 use std::process::Command; 3 4 /// Manual page lookup command 5 pub struct ManCommand; 6 7 impl ChatCommand for ManCommand { 8 fn name(&self) -> &'static str { 9 "man" 10 } 11 fn description(&self) -> &'static str { 12 "Get manual page summary for a command" 13 } 14 fn usage(&self) -> &'static str { 15 "/man <command>" 16 } 17 18 fn execute( 19 &self, 20 args: Vec<String>, 21 _context: &CommandContext, 22 ) -> Result<ChatOpResult, ChatOpError> { 23 if args.is_empty() { 24 return Err(ChatOpError::MissingArguments( 25 "Please specify a command".to_string(), 26 )); 27 } 28 29 let command = &args[0]; 30 31 // Try to get man page using `man` command 32 let match_result = match Command::new("man") 33 .args(&["-f", command]) // whatis format - brief description 34 .output() 35 { 36 Ok(output) => { 37 if output.status.success() { 38 let result = String::from_utf8_lossy(&output.stdout); 39 if result.trim().is_empty() { 40 ChatOpResult::Message(format!("📖 No manual entry found for '{}'", command)) 41 } else { 42 let lines: Vec<String> = result 43 .lines() 44 .take(5) // Limit to first 5 results 45 .map(|line| format!("📖 {}", line.trim())) 46 .collect(); 47 ChatOpResult::Block(lines) 48 } 49 } else { 50 ChatOpResult::Message(format!("📖 No manual entry found for '{}'", command)) 51 } 52 } 53 Err(_) => { 54 // Fallback with some common commands 55 let description = match command.as_str() { 56 "curl" => "transfer a URL - command line tool for transferring data", 57 "grep" => "print lines that match patterns", 58 "awk" => "pattern scanning and processing language", 59 "sed" => "stream editor for filtering and transforming text", 60 "tmux" => "terminal multiplexer", 61 "ssh" => "OpenSSH SSH client (remote login program)", 62 "git" => "the stupid content tracker", 63 "docker" => "A self-sufficient runtime for containers", 64 "vim" => "Vi IMproved, a programmer's text editor", 65 "ls" => "list directory contents", 66 "cd" => "change directory", 67 "cat" => "concatenate files and print on the standard output", 68 "tail" => "output the last part of files", 69 "head" => "output the first part of files", 70 _ => { 71 return Ok(ChatOpResult::Error(format!( 72 "No manual entry found for '{}' and man command not available", 73 command 74 ))) 75 } 76 }; 77 ChatOpResult::Message(format!("📖 {} - {}", command, description)) 78 } 79 }; 80 Ok(match_result) 81 } 82 } 83 84 /// Language-specific documentation lookup 85 pub struct DocCommand; 86 87 impl ChatCommand for DocCommand { 88 fn name(&self) -> &'static str { 89 "doc" 90 } 91 fn description(&self) -> &'static str { 92 "Get language-specific documentation" 93 } 94 fn usage(&self) -> &'static str { 95 "/doc <language> <term>" 96 } 97 98 fn execute( 99 &self, 100 args: Vec<String>, 101 _context: &CommandContext, 102 ) -> Result<ChatOpResult, ChatOpError> { 103 if args.len() < 2 { 104 return Err(ChatOpError::MissingArguments( 105 "Please specify language and term".to_string(), 106 )); 107 } 108 109 let language = args[0].to_lowercase(); 110 let term = &args[1]; 111 112 let doc_url = match language.as_str() { 113 "rust" => format!("https://doc.rust-lang.org/std/?search={}", term), 114 "python" | "py" => format!("https://docs.python.org/3/search.html?q={}", term), 115 "javascript" | "js" => format!("https://developer.mozilla.org/en-US/search?q={}", term), 116 "c" => format!("https://en.cppreference.com/w/c?search={}", term), 117 "cpp" | "c++" => format!("https://en.cppreference.com/w/cpp?search={}", term), 118 "go" => format!("https://pkg.go.dev/search?q={}", term), 119 "java" => format!( 120 "https://docs.oracle.com/en/java/javase/17/docs/api/index.html?search={}", 121 term 122 ), 123 _ => { 124 return Err(ChatOpError::InvalidSyntax(format!( 125 "Unsupported language: {}", 126 language 127 ))) 128 } 129 }; 130 131 Ok(ChatOpResult::Message(format!( 132 "📚 {} docs for '{}': {}", 133 language, term, doc_url 134 ))) 135 } 136 } 137 138 /// Concept explanation command 139 pub struct ExplainCommand; 140 141 impl ChatCommand for ExplainCommand { 142 fn name(&self) -> &'static str { 143 "explain" 144 } 145 fn description(&self) -> &'static str { 146 "Explain programming concepts" 147 } 148 fn usage(&self) -> &'static str { 149 "/explain <concept>" 150 } 151 152 fn execute( 153 &self, 154 args: Vec<String>, 155 _context: &CommandContext, 156 ) -> Result<ChatOpResult, ChatOpError> { 157 if args.is_empty() { 158 return Err(ChatOpError::MissingArguments( 159 "Please specify a concept to explain".to_string(), 160 )); 161 } 162 163 let concept = args.join(" ").to_lowercase(); 164 165 let explanation = match concept.as_str() { 166 "async" | "asynchronous" => { 167 "🔄 **Asynchronous Programming**: A programming paradigm that allows code to run concurrently without blocking. Operations can be initiated and then the program can continue executing other code while waiting for the operation to complete." 168 } 169 "regex" | "regular expression" => { 170 "🔍 **Regular Expressions**: Patterns used to match character combinations in strings. Useful for searching, extracting, and replacing text based on patterns." 171 } 172 "jwt" | "json web token" => { 173 "🔐 **JWT (JSON Web Token)**: A compact, URL-safe means of representing claims between two parties. Used for authentication and secure information transmission." 174 } 175 "rest api" | "restful" => { 176 "🌐 **REST API**: Representational State Transfer - an architectural style for designing networked applications using standard HTTP methods (GET, POST, PUT, DELETE)." 177 } 178 "docker" => { 179 "🐳 **Docker**: A containerization platform that packages applications with their dependencies into lightweight, portable containers." 180 } 181 "git" => { 182 "📝 **Git**: A distributed version control system for tracking changes in source code during software development." 183 } 184 "mutex" | "mutual exclusion" => { 185 "🔒 **Mutex**: A synchronization primitive that prevents multiple threads from accessing shared data simultaneously, preventing race conditions." 186 } 187 "blockchain" => { 188 "⛓️ **Blockchain**: A distributed ledger technology that maintains a continuously growing list of records (blocks) linked using cryptography." 189 } 190 _ => { 191 return Ok(ChatOpResult::Message(format!("🤔 I don't have an explanation for '{}' yet. Try searching online or ask a more specific question.", concept))); 192 } 193 }; 194 195 Ok(ChatOpResult::Message(explanation.to_string())) 196 } 197 } 198 199 /// Cheat sheet lookup command 200 pub struct CheatCommand; 201 202 impl ChatCommand for CheatCommand { 203 fn name(&self) -> &'static str { 204 "cheat" 205 } 206 fn description(&self) -> &'static str { 207 "Get cheat sheets from cht.sh" 208 } 209 fn usage(&self) -> &'static str { 210 "/cheat <term>" 211 } 212 213 fn execute( 214 &self, 215 args: Vec<String>, 216 _context: &CommandContext, 217 ) -> Result<ChatOpResult, ChatOpError> { 218 if args.is_empty() { 219 return Err(ChatOpError::MissingArguments( 220 "Please specify a term for the cheat sheet".to_string(), 221 )); 222 } 223 224 let term = args.join("+"); 225 226 // Try to fetch from cht.sh with plain text output and timeout 227 match Command::new("curl") 228 .args(&[ 229 "-s", 230 "--max-time", 231 "5", 232 &format!("https://cht.sh/{}?T", term), 233 ]) 234 .output() 235 { 236 Ok(output) => { 237 if output.status.success() { 238 let result = String::from_utf8_lossy(&output.stdout); 239 let lines: Vec<String> = result 240 .lines() 241 .take(20) // Limit to prevent spam but allow context 242 .map(|line| line.to_string()) 243 .collect(); 244 245 if lines.is_empty() || lines[0].contains("Unknown") { 246 Ok(ChatOpResult::Message(format!( 247 "📋 No cheat sheet found for '{}'", 248 args.join(" ") 249 ))) 250 } else { 251 Ok(ChatOpResult::CodeBlock( 252 lines.join("\n"), 253 Some("text".to_string()), 254 )) 255 } 256 } else { 257 Err(ChatOpError::NetworkError( 258 "Failed to fetch cheat sheet".to_string(), 259 )) 260 } 261 } 262 Err(_) => { 263 // Fallback message 264 Ok(ChatOpResult::Message(format!( 265 "📋 Try: https://cht.sh/{}", 266 term 267 ))) 268 } 269 } 270 } 271 } 272 273 /// StackOverflow search command 274 pub struct StackOverflowCommand; 275 276 impl ChatCommand for StackOverflowCommand { 277 fn name(&self) -> &'static str { 278 "so" 279 } 280 fn description(&self) -> &'static str { 281 "Search StackOverflow" 282 } 283 fn usage(&self) -> &'static str { 284 "/so <query>" 285 } 286 fn aliases(&self) -> Vec<&'static str> { 287 vec!["stackoverflow"] 288 } 289 290 fn execute( 291 &self, 292 args: Vec<String>, 293 _context: &CommandContext, 294 ) -> Result<ChatOpResult, ChatOpError> { 295 if args.is_empty() { 296 return Err(ChatOpError::MissingArguments( 297 "Please specify a search query".to_string(), 298 )); 299 } 300 301 let query = args.join(" "); 302 let encoded_query = query.replace(" ", "+"); 303 let url = format!("https://stackoverflow.com/search?q={}", encoded_query); 304 305 Ok(ChatOpResult::Message(format!( 306 "🟠 StackOverflow search for '{}': {}", 307 query, url 308 ))) 309 } 310 } 311 312 /// Reference links command 313 pub struct RefCommand; 314 315 impl ChatCommand for RefCommand { 316 fn name(&self) -> &'static str { 317 "ref" 318 } 319 fn description(&self) -> &'static str { 320 "Get official reference links" 321 } 322 fn usage(&self) -> &'static str { 323 "/ref <library/language>" 324 } 325 326 fn execute( 327 &self, 328 args: Vec<String>, 329 _context: &CommandContext, 330 ) -> Result<ChatOpResult, ChatOpError> { 331 if args.is_empty() { 332 return Err(ChatOpError::MissingArguments( 333 "Please specify a library or language".to_string(), 334 )); 335 } 336 337 let library = args[0].to_lowercase(); 338 339 let reference = match library.as_str() { 340 "rust" => ("🦀 Rust", "https://doc.rust-lang.org/std/"), 341 "python" => ("🐍 Python", "https://docs.python.org/3/"), 342 "javascript" | "js" => ( 343 "📜 JavaScript", 344 "https://developer.mozilla.org/en-US/docs/Web/JavaScript", 345 ), 346 "react" => ("⚛️ React", "https://reactjs.org/docs/"), 347 "vue" => ("💚 Vue.js", "https://vuejs.org/guide/"), 348 "node" | "nodejs" => ("🟢 Node.js", "https://nodejs.org/en/docs/"), 349 "docker" => ("🐳 Docker", "https://docs.docker.com/"), 350 "git" => ("📝 Git", "https://git-scm.com/docs"), 351 "linux" => ("🐧 Linux", "https://man7.org/linux/man-pages/"), 352 "postgresql" | "postgres" => ("🐘 PostgreSQL", "https://www.postgresql.org/docs/"), 353 "mysql" => ("🐬 MySQL", "https://dev.mysql.com/doc/"), 354 "redis" => ("🔴 Redis", "https://redis.io/documentation"), 355 _ => { 356 return Ok(ChatOpResult::Message(format!( 357 "🔍 No reference found for '{}'. Try a web search instead.", 358 library 359 ))) 360 } 361 }; 362 363 Ok(ChatOpResult::Message(format!( 364 "{} Reference: {}", 365 reference.0, reference.1 366 ))) 367 } 368 }