### Basic CLI Integration Test Setup Source: https://github.com/rust-cli/book/blob/master/src/tutorial/testing.md This Rust code sets up a basic integration test for a CLI application. It uses the `assert_cmd` crate to execute the project's binary and includes a test case to verify that the program exits with an error when the input file does not exist. The `#[test]` attribute marks the function as a test, and `Command::cargo_bin("grrs")` is used to get a handle to the binary. ```rust use assert_cmd::Command; #[test] fn file_doesnt_exist() { let mut cmd = Command::cargo_bin("grrs").unwrap(); cmd.arg("nonexistent_file.txt").assert().failure(); } ``` -------------------------------- ### Build Rust CLI Book with mdBook Source: https://github.com/rust-cli/book/blob/master/README.md Builds the Command Line Applications in Rust book using the installed mdBook tool. The output is placed in the 'book' subdirectory, and can be viewed by opening 'book/index.html' in a web browser. ```bash $ mdbook build ``` -------------------------------- ### Signal Handling in Rust Source: https://context7.com/rust-cli/book/llms.txt Provides examples for handling OS signals like Ctrl+C, using both simple handlers and channel-based integration for complex event loops. ```rust use std::{thread, time::Duration}; fn main() { ctrlc::set_handler(move || { println!("received Ctrl+C!"); }) .expect("Error setting Ctrl-C handler"); thread::sleep(Duration::from_secs(2)); } ``` ```rust use anyhow::Result; use crossbeam_channel::{Receiver, bounded, select, tick}; use std::time::Duration; fn ctrl_channel() -> Result, ctrlc::Error> { let (sender, receiver) = bounded(100); ctrlc::set_handler(move || { let _ = sender.send(()); })?; Ok(receiver) } fn main() -> Result<()> { let ctrl_c_events = ctrl_channel()?; let ticks = tick(Duration::from_secs(1)); loop { select! { recv(ticks) -> _ => { println!("working!"); } recv(ctrl_c_events) -> _ => { println!(); println!("Goodbye!"); break; } } } Ok(())} ``` -------------------------------- ### Install mdBook for Building Rust CLI Book Source: https://github.com/rust-cli/book/blob/master/README.md Installs the mdBook tool, which is required to build the Command Line Applications in Rust book. This command uses Cargo, the Rust package manager. ```bash $ cargo install mdbook ``` -------------------------------- ### ripgrep JSON output example Source: https://github.com/rust-cli/book/blob/master/src/in-depth/machine-communication.md This example shows the JSON output generated by the `ripgrep` tool when the `--json` flag is used. Each JSON object represents a distinct event during the search process, such as the start of a search in a file, a match found, or the end of a search. This line-delimited JSON format allows for real-time processing of search results. ```console $ rg default --json {"type":"begin","data":{"path":{"text":"src/lib.rs"}}} {"type":"match","data":{"path":{"text":"src/lib.rs"},"lines":{"text":" Output::default()\n"},"line_number":37,"absolute_offset":761,"submatches":[{"match":{"text":"default"},"start":12,"end":19}]}} {"type":"end","data":{"path":{"text":"src/lib.rs"},"binary_offset":null,"stats":{"elapsed":{"secs":0,"nanos":137622,"human":"0.000138s"},"searches":1,"searches_with_match":1,"bytes_searched":6064,"bytes_printed":256,"matched_lines":1,"matches":1}}} {"type":"begin","data":{"path":{"text":"src/components/span.rs"}}} {"type":"match","data":{"path":{"text":"src/components/span.rs"},"lines":{"text":" Span::default()\n"},"line_number":6,"absolute_offset":117,"submatches":[{"match":{"text":"default"},"start":10,"end":17}]}} {"type":"end","data":{"path":{"text":"src/components/span.rs"},"binary_offset":null,"stats":{"elapsed":{"secs":0,"nanos":22025,"human":"0.000022s"},"searches":1,"searches_with_match":1,"bytes_searched":5221,"bytes_printed":277,"matched_lines":1,"matches":1}}} {"data":{"elapsed_total":{"human":"0.006995s","nanos":6994920,"secs":0},"stats":{"bytes_printed":533,"bytes_searched":11285,"elapsed":{"human":"0.000160s","nanos":159647,"secs":0},"matched_lines":2,"matches":2,"searches":2,"searches_with_match":2}},"type":"summary"} ``` -------------------------------- ### Rust: Implementing Error Handling with anyhow Source: https://github.com/rust-cli/book/blob/master/src/tutorial/errors.md Provides a complete example of implementing error handling using the `anyhow` crate. This snippet likely includes the necessary imports and function definitions to leverage `anyhow::Context` for creating rich error messages and error chains. ```rust /* {{#include errors-impl.rs}} */ ``` -------------------------------- ### Rust: Custom Error Type for Enhanced Error Messages Source: https://github.com/rust-cli/book/blob/master/src/tutorial/errors.md Illustrates how to define a custom error type in Rust to provide more informative error messages. This approach wraps the original error and adds context, improving the clarity of error reporting when operations fail. The example shows a common pattern for creating user-friendly error messages. ```rust /* {{#include errors-custom.rs}} */ ``` -------------------------------- ### Print "Hello World" in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/output.md The most basic way to print a string to standard output in Rust using the `println!` macro. ```rust println!("Hello World"); ``` -------------------------------- ### Standard Console Output in Rust Source: https://context7.com/rust-cli/book/llms.txt Demonstrates printing to standard output and error streams using println! and eprintln!. It highlights the use of Display and Debug traits for formatting variables. ```rust fn main() { let x = 42; println!("My lucky number is {}.", x); let xs = vec![1, 2, 3]; println!("The list is: {:?}", xs); println!("This is information"); eprintln!("This is an error! :("); } ``` -------------------------------- ### Publish Crate to Crates.io Source: https://context7.com/rust-cli/book/llms.txt Provides the necessary Cargo.toml configuration and CLI commands to prepare and publish a Rust project to the crates.io registry. ```toml [package] name = "grrs" version = "0.1.0" authors = ["Your Name "] license = "MIT OR Apache-2.0" description = "A tool to search files" readme = "README.md" homepage = "https://github.com/you/grrs" repository = "https://github.com/you/grrs" keywords = ["cli", "search", "demo"] categories = ["command-line-utilities"] ``` ```bash # Login to crates.io (one-time setup) cargo login # Publish your crate cargo publish # Install a published crate cargo install grrs ``` -------------------------------- ### Unwrap File Read Result in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/errors.md Shows a concise way to get the content of a file using the unwrap method on the Result. If the file read operation fails, unwrap will cause the program to panic. This is suitable when the program cannot continue without the file's content. ```rust let content = std::fs::read_to_string("test.txt").unwrap(); ``` -------------------------------- ### Complete Rust CLI application using Clap Source: https://github.com/rust-cli/book/blob/master/src/tutorial/cli-args.md A complete Rust program demonstrating command-line argument parsing using the Clap library. It includes argument definition, parsing, and basic output. ```rust use clap::Parser; /// Search for a pattern in a file and display the lines that contain it #[derive(Parser)] struct Cli { /// The pattern to look for pattern: String, /// The path to the file to search in path: std::path::PathBuf, } fn main() { let cli = Cli::parse(); println!("pattern: \"{:?}\"", cli.pattern); println!("path: \"{:?}\"", cli.path); } ``` -------------------------------- ### Load application configuration using confy Source: https://github.com/rust-cli/book/blob/master/src/in-depth/config-files.md Demonstrates how to use the confy crate to automatically load and deserialize configuration data into a Rust struct. This approach simplifies cross-platform file management but offers limited customization. ```rust #[derive(Debug, Serialize, Deserialize)] struct MyConfig { name: String, comfy: bool, foo: i64, } fn main() -> Result<(), io::Error> { let cfg: MyConfig = confy::load("my_app")?; println!("{:#?}", cfg); Ok(()) } ``` -------------------------------- ### Modularizing Rust Projects Source: https://github.com/rust-cli/book/blob/master/src/tutorial/testing.md Illustrates the pattern of moving core logic from a binary crate (main.rs) into a library crate (lib.rs) to improve code reusability and organization. ```rust // src/lib.rs pub fn find_matches(content: &str, pattern: &str, mut writer: impl std::io::Write) -> std::io::Result<()> { for line in content.lines() { if line.contains(pattern) { writeln!(writer, "{}", line)?; } } Ok(()) } // src/main.rs fn main() { let content = "foo\nbar"; grrs::find_matches(content, "foo", std::io::stdout()).unwrap(); } ``` -------------------------------- ### Testable Code with Writer Abstraction in Rust Source: https://context7.com/rust-cli/book/llms.txt Demonstrates how to decouple CLI logic from stdout by accepting a generic Write trait, enabling unit testing of output streams. ```rust use anyhow::{Context, Result}; use clap::Parser; #[derive(Parser)] struct Cli { pattern: String, path: std::path::PathBuf, } fn main() -> Result<()> { let args = Cli::parse(); let content = std::fs::read_to_string(&args.path) .with_context(|| format!("could not read file `{}`", args.path.display()))?; find_matches(&content, &args.pattern, &mut std::io::stdout()); Ok(()) } fn find_matches(content: &str, pattern: &str, mut writer: impl std::io::Write) { for line in content.lines() { if line.contains(pattern) { writeln!(writer, "{}", line); } } } #[test] fn find_a_match() { let mut result = Vec::new(); find_matches("lorem ipsum\ndolor sit amet", "lorem", &mut result); assert_eq!(result, b"lorem ipsum\n"); } ``` -------------------------------- ### Formatted Printing with `println!` in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/output.md Demonstrates how to use the `println!` macro with placeholders to insert variables into strings. It covers default human-readable formatting and debug formatting using `{:?}`. ```rust let x = 42; println!("My lucky number is {}.", x); ``` ```rust let xs = vec![1, 2, 3]; println!("The list is: {:?}", xs); ``` -------------------------------- ### Read and Filter File Content in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/impl-draft.md Demonstrates the basic implementation of reading a file into a string and iterating over its lines to find a specific pattern. It uses the expect method for basic error handling and prints matching lines to standard output. ```rust let content = std::fs::read_to_string(&args.path).expect("could not read file"); for line in content.lines() { if line.contains(&args.pattern) { println!("{}", line); } } ``` -------------------------------- ### High-Performance Output with BufWriter in Rust Source: https://context7.com/rust-cli/book/llms.txt Shows how to wrap stdout in a BufWriter to minimize system calls when performing frequent write operations. ```rust use std::io::{self, Write}; fn main() { let stdout = io::stdout(); let mut handle = io::BufWriter::new(stdout); writeln!(handle, "foo: {}", 42).unwrap(); } ``` -------------------------------- ### Integration Testing with assert_cmd in Rust Source: https://context7.com/rust-cli/book/llms.txt Uses assert_cmd and predicates to perform integration testing on CLI binaries, verifying success/failure states and output content. ```rust use assert_cmd::cargo::*; use predicates::prelude::*; use assert_fs::prelude::*; #[test] fn file_doesnt_exist() -> Result<(), Box> { let mut cmd = cargo_bin_cmd!("grrs"); cmd.arg("foobar").arg("test/file/doesnt/exist"); cmd.assert() .failure() .stderr(predicate::str::contains("could not read file")); Ok(()) } #[test] fn find_content_in_file() -> Result<(), Box> { let file = assert_fs::NamedTempFile::new("sample.txt")?; file.write_str("A test\nActual content\nMore content\nAnother test")?; let mut cmd = cargo_bin_cmd!("grrs"); cmd.arg("test").arg(file.path()); cmd.assert() .success() .stdout(predicate::str::contains("A test\nAnother test")); Ok(())} ``` -------------------------------- ### Define CLI Arguments with clap Source: https://github.com/rust-cli/book/blob/master/src/in-depth/docs.md This Rust code snippet demonstrates how to define command-line arguments for a CLI application using the `clap` crate. It specifies arguments like 'file' and 'count' with their types and help messages. This definition is crucial for generating `--help` output. ```rust use std::path::PathBuf; #[derive(Parser)] pub struct Head { /// file to load pub file: PathBuf, /// how many lines to print #[arg(short = "n", default_value = "5")] pub count: usize, } ``` -------------------------------- ### Generate Man Page with clap_mangen in build.rs Source: https://github.com/rust-cli/book/blob/master/src/in-depth/docs.md This Rust code snippet is intended for a `build.rs` file. It uses `clap_mangen` to generate a man page (`head.1`) for the CLI application at compile time. It requires the `clap` crate and assumes the CLI definition is in `src/cli.rs`. ```rust use clap::CommandFactory; #[path="src/cli.rs"] mod cli; fn main() -> std::io::Result<()> { let out_dir = std::path::PathBuf::from(std::env::var_os("OUT_DIR").ok_or_else(|| std::io::ErrorKind::NotFound)?); let cmd = cli::Head::command(); let man = clap_mangen::Man::new(cmd); let mut buffer: Vec = Default::default(); man.render(&mut buffer)?; std::fs::write(out_dir.join("head.1"), buffer)?; Ok(()) } ``` -------------------------------- ### Implement Basic File Search in Rust Source: https://context7.com/rust-cli/book/llms.txt A basic implementation to read a file and search for lines containing a specific pattern. This version loads the entire file into memory, which may not be suitable for very large files. It uses clap for argument parsing. ```rust use clap::Parser; /// Search for a pattern in a file and display the lines that contain it. #[derive(Parser)] struct Cli { /// The pattern to look for pattern: String, /// The path to the file to read path: std::path::PathBuf, } fn main() { let args = Cli::parse(); let content = std::fs::read_to_string(&args.path).expect("could not read file"); for line in content.lines() { if line.contains(&args.pattern) { println!("{}", line); } } } ``` -------------------------------- ### Support JSON Output for CLI Source: https://context7.com/rust-cli/book/llms.txt Utilizes clap for argument parsing and serde_json for generating structured output. This allows the CLI to toggle between human-readable and machine-parsable formats. ```rust use clap::Parser; use serde_json::json; #[derive(Parser)] struct Cli { #[arg(long = "json")] json: bool, } fn main() { let args = Cli::parse(); if args.json { println!( "{}", json!({ "type": "message", "content": "Hello world", }) ); } else { println!("Hello world"); } } ``` -------------------------------- ### Configure structured logging with env_logger in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/output.md Demonstrates how to use the log crate for categorized messages and env_logger as an adapter to output logs based on environment variables. This allows for flexible debugging levels like info, warn, and error. ```rust use log::{info, warn}; fn main() { env_logger::init(); info!("starting up"); warn!("oops, nothing implemented!"); } ``` -------------------------------- ### Configure Cargo.toml Metadata Source: https://github.com/rust-cli/book/blob/master/src/tutorial/packaging.md This snippet demonstrates the required metadata fields in the Cargo.toml file to ensure a Rust crate is properly documented and licensed when published to crates.io. ```toml [package] name = "grrs" version = "0.1.0" authors = ["Your Name "] license = "MIT OR Apache-2.0" description = "A tool to search files" readme = "README.md" homepage = "https://github.com/you/grrs" repository = "https://github.com/you/grrs" keywords = ["cli", "search", "demo"] categories = ["command-line-utilities"] ``` -------------------------------- ### Test Rust CLI Book with mdBook Source: https://github.com/rust-cli/book/blob/master/README.md Runs the tests for the Command Line Applications in Rust book using the mdBook tool. This ensures the integrity and correctness of the book's content. ```bash $ mdbook test ``` -------------------------------- ### Custom Panic Handler with human-panic in Rust Source: https://github.com/rust-cli/book/blob/master/src/in-depth/human-communication.md Integrates the 'human-panic' crate to replace the default panic handler with a user-friendly message. This involves importing the `setup_panic!` macro and calling it at the beginning of the `main` function. It provides a detailed report for users to submit. ```rust use human_panic::setup_panic; fn main() { setup_panic!(); panic!("Hello world") } ``` -------------------------------- ### Error Handling with Anyhow Context in Rust Source: https://context7.com/rust-cli/book/llms.txt Leverage the anyhow crate for ergonomic error handling with context chains. Add `anyhow = "1.0"` to your Cargo.toml. It provides a `Context` trait and a `Result` type alias for simplified error management. ```rust use anyhow::{Context, Result}; use clap::Parser; /// Search for a pattern in a file and display the lines that contain it. #[derive(Parser)] struct Cli { /// The pattern to look for pattern: String, /// The path to the file to read path: std::path::PathBuf, } fn main() -> Result<()> { let args = Cli::parse(); let content = std::fs::read_to_string(&args.path) .with_context(|| format!("could not read file `{}`", args.path.display()))?; for line in content.lines() { if line.contains(&args.pattern) { println!("{}", line); } } Ok(()) } ``` -------------------------------- ### User-Friendly Panic Output with human-panic Source: https://github.com/rust-cli/book/blob/master/src/in-depth/human-communication.md Demonstrates the output generated by the 'human-panic' crate when a panic occurs. It displays an apologetic message, explains the crash, provides a path to a detailed report file, and includes author contact information for reporting. ```console Well, this is embarrassing. foo had a problem and crashed. To help us diagnose the problem you can send us a crash report. We have generated a report file at "/var/folders/n3/dkk459k908lcmkzwcmq0tcv00000gn/T/report-738e1bec-5585-47a4-8158-f1f7227f0168.toml". Submit an issue or email with the subject of "foo Crash Report" and include the report as an attachment. - Authors: Your Name We take privacy seriously, and do not perform any automated error collection. In order to improve the software, we rely on people to submit reports. Thank you kindly! ``` -------------------------------- ### Locking stdout for Writing in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/output.md Demonstrates how to acquire a lock on `stdout` to prevent repeated locking and unlocking overhead when writing multiple times, which can improve performance. ```rust use std::io::{self, Write}; let stdout = io::stdout(); // get the global stdout entity let mut handle = stdout.lock(); // acquire a lock on it writeln!(handle, "foo: {}", 42); // add `?` if you care about errors here ``` -------------------------------- ### Using Byte String Literals in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/testing.md Demonstrates the use of the 'b' prefix to create byte string literals, which have the type &[u8] instead of &str, useful for binary data handling. ```rust let data: Vec = vec![102, 111, 111]; assert_eq!(data, b"foo"); ``` -------------------------------- ### Progress Bars with Indicatif in Rust Source: https://context7.com/rust-cli/book/llms.txt Utilizes the indicatif crate to implement progress bars for long-running CLI tasks, providing visual feedback to the user. ```rust fn main() { let pb = indicatif::ProgressBar::new(100); for i in 0..100 { do_hard_work(); pb.println(format!("[+] finished #{}", i)); pb.inc(1); } pb.finish_with_message("done"); } fn do_hard_work() { use std::thread; use std::time::Duration; thread::sleep(Duration::from_millis(250)); } ``` -------------------------------- ### Manually map CLI arguments to a struct Source: https://github.com/rust-cli/book/blob/master/src/tutorial/cli-args.md Demonstrates the manual conversion of raw string arguments from the operating system into a structured Cli object. This method requires manual indexing and type conversion. ```rust let args: Vec = std::env::args().collect(); let pattern = args[1].clone(); let path = std::path::PathBuf::from(args[2].clone()); let args = Cli { pattern, path, }; ``` -------------------------------- ### Define a unit test in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/testing.md Demonstrates how to use the #[test] attribute to mark a function as a test case. The function uses assert_eq! to verify that the output of a target function matches the expected value. ```rust # fn answer() -> i32 { # 42 # } # #[test] fn check_answer_validity() { assert_eq!(answer(), 42); } ``` -------------------------------- ### Add Testing Dependencies to Cargo.toml Source: https://github.com/rust-cli/book/blob/master/src/tutorial/testing.md This snippet shows how to add `assert_cmd` and `predicates` as development dependencies in your `Cargo.toml` file. These crates are essential for writing integration tests for your CLI application, allowing you to run the binary and assert its output and exit status. ```toml [ "assert_cmd", "predicates" ] ``` -------------------------------- ### Read from Stdin in Rust CLI Source: https://context7.com/rust-cli/book/llms.txt Implements logic to read input from either a file path or standard input when '-' is provided as an argument. It uses BufReader for efficient I/O processing. ```rust use clap::{CommandFactory, Parser}; use std::{ fs::File, io::{BufRead, BufReader, IsTerminal, stdin}, path::PathBuf, }; #[derive(Parser)] #[command(arg_required_else_help = true)] struct Cli { /// The path to the file to read, use - to read from stdin file: PathBuf, } fn main() { let args = Cli::parse(); let word_count; let mut file = args.file; if file == PathBuf::from("-") { if stdin().is_terminal() { Cli::command().print_help().unwrap(); ::std::process::exit(2); } file = PathBuf::from(""); word_count = words_in_buf_reader(BufReader::new(stdin().lock())); } else { word_count = words_in_buf_reader(BufReader::new(File::open(&file).unwrap())); } println!("Words from {}: {}", file.to_string_lossy(), word_count) } fn words_in_buf_reader(buf_reader: R) -> usize { let mut count = 0; for line in buf_reader.lines() { count += line.unwrap().split(' ').count() } count } ``` -------------------------------- ### Add Temporary File Generation Dependency Source: https://github.com/rust-cli/book/blob/master/src/tutorial/testing.md This TOML snippet demonstrates adding the `assert_fs` crate to the `dev-dependencies` section of your `Cargo.toml`. This crate is used for creating and managing temporary files within your integration tests, which is useful for testing scenarios where your CLI application interacts with files. ```toml "assert_fs" ``` -------------------------------- ### Handle Program Exit Codes with `exitcode` Crate in Rust Source: https://github.com/rust-cli/book/blob/master/src/in-depth/exit-code.md Demonstrates how to use the `exitcode` crate in Rust to set appropriate exit codes for different program outcomes. It shows handling successful execution with `exitcode::OK` and various error conditions like configuration errors (`exitcode::CONFIG`) and general data errors (`exitcode::DATAERR`). This requires adding the `exitcode` crate as a dependency in `Cargo.toml`. ```rust fn main() { // ...actual work... match result { Ok(_) => { println!("Done!"); std::process::exit(exitcode::OK); } Err(CustomError::CantReadConfig(e)) => { eprintln!("Error: {}", e); std::process::exit(exitcode::CONFIG); } Err(e) => { eprintln!("Error: {}", e); std::process::exit(exitcode::DATAERR); } } } ``` -------------------------------- ### Parse CLI Arguments with Clap Derive in Rust Source: https://context7.com/rust-cli/book/llms.txt Utilize the clap crate's derive feature for declarative argument parsing. This provides automatic help messages, validation, and shell completions. Add `clap = { version = "4.0", features = ["derive"] }` to your Cargo.toml. ```rust use clap::Parser; /// Search for a pattern in a file and display the lines that contain it. #[derive(Parser)] struct Cli { /// The pattern to look for pattern: String, /// The path to the file to read path: std::path::PathBuf, } fn main() { let args = Cli::parse(); println!("pattern: {:?}, path: {:?}", args.pattern, args.path) } ``` -------------------------------- ### Implement progress bars with indicatif in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/output.md Uses the indicatif crate to provide visual feedback for long-running tasks. This helps users track progress in CLI applications that perform time-consuming operations. ```rust use indicatif::ProgressBar; use std::thread; use std::time::Duration; fn main() { let pb = ProgressBar::new(100); for _ in 0..100 { pb.inc(1); thread::sleep(Duration::from_millis(10)); } pb.finish(); } ``` -------------------------------- ### Rust: Using anyhow::Context for Error Chaining Source: https://github.com/rust-cli/book/blob/master/src/tutorial/errors.md Shows how to use the `anyhow` crate's `Context` trait to add descriptive messages to errors while preserving the original error chain. This allows for detailed error reporting that includes the root cause, making debugging easier. Requires adding `anyhow = "1.0"` to Cargo.toml. ```rust /* {{#include errors-exit.rs}} */ ``` -------------------------------- ### Parse Raw Command Line Arguments with std::env in Rust Source: https://context7.com/rust-cli/book/llms.txt Access raw command-line arguments as an iterator of strings using `std::env::args()`. The first argument is the program name, followed by user-provided arguments. This method is basic and requires manual parsing and error handling. ```rust fn main() { let pattern = std::env::args().nth(1).expect("no pattern given"); let path = std::env::args().nth(2).expect("no path given"); println!("pattern: {:?}, path: {:?}", pattern, path) } ``` -------------------------------- ### Buffered Writing to stdout in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/output.md Explains how to improve printing performance by using `std::io::BufWriter` to buffer output before flushing it to the terminal, reducing the number of system calls. ```rust use std::io::{self, Write}; let stdout = io::stdout(); // get the global stdout entity let mut handle = io::BufWriter::new(stdout); // optional: wrap that handle in a buffer writeln!(handle, "foo: {}", 42); // add `?` if you care about errors here ``` -------------------------------- ### CLI Integration Test with Temporary File Source: https://github.com/rust-cli/book/blob/master/src/tutorial/testing.md This Rust code snippet illustrates an integration test that utilizes the `assert_fs` crate to create a temporary file. The test writes specific content to this temporary file and then runs the CLI application, asserting that the program correctly processes the file and produces the expected output. The temporary file is automatically cleaned up when the `file` variable goes out of scope. ```rust use assert_cmd::Command; use assert_fs::NamedTempFile; #[test] fn find_content() { let file = NamedTempFile::new().unwrap(); file.write_str("Hello world ").unwrap(); let mut cmd = Command::cargo_bin("grrs").unwrap(); cmd.arg(file.path()).arg("world").assert().success().stdout("Hello world\n"); } ``` -------------------------------- ### Printing Errors to stderr in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/output.md Shows how to print messages to standard error (stderr) using the `eprintln!` macro, differentiating it from standard output (`stdout`) for better error handling and output redirection. ```rust println!("This is information"); eprintln!("This is an error! :("); ``` -------------------------------- ### Parse CLI arguments and handle execution with Clap Source: https://github.com/rust-cli/book/blob/master/src/tutorial/cli-args.md Parses command-line arguments into the `Cli` struct and executes the main program logic. Clap handles argument validation, help messages, and errors automatically. ```rust fn main() { let cli = Cli::parse(); println!("pattern: \"{:?}\"", cli.pattern); println!("path: \"{:?}\"", cli.path); } ``` -------------------------------- ### Read and count words from a file in Rust Source: https://github.com/rust-cli/book/blob/master/src/in-depth/machine-communication.md This snippet demonstrates reading a file path from command-line arguments and counting words line by line. It relies on standard file I/O operations to process the contents. ```rust use std::env; use std::fs::File; use std::io::{self, BufRead, BufReader}; fn main() -> io::Result<()> { let args: Vec = env::args().collect(); let file = File::open(&args[1])?; let reader = BufReader::new(file); let mut count = 0; for line in reader.lines() { count += line?.split_whitespace().count(); } println!("Words in {}: {}", args[1], count); Ok(()) ``` -------------------------------- ### Generate JSON output using serde_json macro in Rust Source: https://github.com/rust-cli/book/blob/master/src/in-depth/machine-communication.md This Rust code snippet demonstrates how to generate JSON output for machine readability using the `json!` macro from the `serde_json` crate. It's useful for sending structured messages from a CLI application. The output can be toggled between plain text and JSON based on command-line arguments. ```rust use std::env; fn main() { let args: Vec = env::args().collect(); let json_output = args.len() > 1 && args[1] == "--json"; if json_output { // Using the json! macro from serde_json let message = "Hello world"; println!(json!({{ "type": "message", "content": "{}" }}), message); } else { println!("Hello world"); } } ``` -------------------------------- ### Structure CLI Arguments as Data Types in Rust Source: https://context7.com/rust-cli/book/llms.txt Define a struct to represent CLI arguments for better maintainability and type safety. Use `PathBuf` for file system paths to ensure cross-platform compatibility. This approach improves code organization over raw argument parsing. ```rust struct Cli { pattern: String, path: std::path::PathBuf, } fn main() { let pattern = std::env::args().nth(1).expect("no pattern given"); let path = std::env::args().nth(2).expect("no path given"); let args = Cli { pattern, path: std::path::PathBuf::from(path), }; println!("pattern: {:?}, path: {:?}", args.pattern, args.path); } ``` -------------------------------- ### Retrieve raw command-line arguments in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/cli-args.md Uses the standard library's std::env::args function to collect command-line arguments as an iterator. The first element is the program name, followed by user-provided arguments. ```rust use std::env; fn main() { let args: Vec = env::args().collect(); let pattern = &args[1]; let path = &args[2]; println!("pattern: {:?}, path: {:?}", pattern, path); } ``` -------------------------------- ### Handle File Read Results with Match in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/errors.md Demonstrates how to use a match statement to handle the Result of reading a file. It checks if the operation was Ok and prints the content, or if it was an Err and prints the error message. This is a fundamental way to deal with fallible operations in Rust. ```rust let result = std::fs::read_to_string("test.txt"); match result { Ok(content) => { println!("File content: {}", content); }, Err(error) => { println!("Oh noes: {}", error); } } ``` -------------------------------- ### Expected test execution output Source: https://github.com/rust-cli/book/blob/master/src/tutorial/testing.md Shows the standard console output generated by cargo test when a test suite executes successfully. ```text running 1 test test check_answer_validity ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -------------------------------- ### Define CLI arguments as a Rust struct Source: https://github.com/rust-cli/book/blob/master/src/tutorial/cli-args.md Defines a custom data structure to represent CLI inputs, using PathBuf for cross-platform file path handling. This approach organizes program inputs into typed fields. ```rust struct Cli { pattern: String, path: std::path::PathBuf, } ``` -------------------------------- ### Rust: Using the '?' Operator for Error Handling Source: https://github.com/rust-cli/book/blob/master/src/tutorial/errors.md Demonstrates the use of the '?' operator to simplify error handling when working with Result types, specifically for reading file content. It automatically propagates errors, making the code more concise. The function returns a Result to allow the '?' operator to be used. ```rust fn main() -> Result<(), Box> { let content = std::fs::read_to_string("test.txt")?; println!("file content: {}", content); Ok(()) } ``` -------------------------------- ### Handle File Read Errors by Returning in Rust Source: https://github.com/rust-cli/book/blob/master/src/tutorial/errors.md Illustrates how to handle a file read error by returning it from the function using the `return Err(error.into())` syntax. This requires the function to have a return type that is compatible with `Result`, such as `Result<(), Box>`. ```rust fn main() -> Result<(), Box> { let result = std::fs::read_to_string("test.txt"); let content = match result { Ok(content) => { content }, Err(error) => { return Err(error.into()); } }; println!("file content: {}", content); Ok(()) } ```