fixed capitalization issue

This commit is contained in:
candle 2025-07-10 21:19:18 -04:00
parent 99e3eba54a
commit 673013f1fb
5 changed files with 78 additions and 57 deletions

View File

@ -2,6 +2,11 @@
`motd` is a command line utility which outputs a (semi) intelligible, randomly generated message to your standard output.
```
motd -t "$HOME is where the {noun} is."
/home/admin is where the dragon is.
```
## Build and Install
##### Requirements
`git`, `rust`/`rustup`/`cargo`
@ -22,7 +27,7 @@ You may remove the cloned directory.
`motd` is best when customized with your own word pools and templates.
`motd` will look for a `$HOME/.motdrc`, `$XDG_CONFIG_HOME/.motdrc`, or `$XDG_CONFIG_HOME/motd/motdrc` file and use the settings there as defaults when running `motd` with no flags. If somehow `motd` is configured in a way that would result in an empty word list, it will fallback to the built in defaults.
Run `motd -h` to view all options. `motd` will look for a `$HOME/.motdrc`, `$XDG_CONFIG_HOME/.motdrc`, or `$XDG_CONFIG_HOME/motd/motdrc` file and use the settings there as defaults when running `motd` with no flags. If somehow `motd` is configured in a way that would result in an empty word list, it will fallback to the built in defaults.
```
# Example motdrc
@ -86,7 +91,7 @@ motd -p adverbs > $XDG_CONFIG_HOME/motd/adverbs
motd -p locations > $XDG_CONFIG_HOME/motd/locations
```
Words are separated by line, meaning you can have multiple words treated as a single unit.\
Re-defining a word will not add an additional entry to the word pool.
Re-defining a word will not add an additional entry to the word pool.\
Lines beginning with a `!` are actively removed from their respective word pool.\
Lines beginning with a `#` are ignored as comments.
Lines with the format `$()` can be `bash` expressions which are evaluated at runtime.\

View File

@ -1,6 +1,6 @@
use crate::cli::RcArgs;
use crate::words::WordList;
use crate::words::{WordType, WORD_TYPES};
use crate::words::{WORD_TYPES, WordType};
use regex::Regex;
use std::env;
use std::fs;
@ -27,7 +27,8 @@ impl Config {
let mut templates = Vec::new();
let mut template_exclusions = Vec::new();
for word_type in WORD_TYPES {
let (word_list, exclusion_list) = load_word_list_with_exclusions(&config_dir.join(word_type.name()));
let (word_list, exclusion_list) =
load_word_list_with_exclusions(&config_dir.join(word_type.name()));
if !word_list.is_empty() {
match word_type {
WordType::Adjective => words.adjectives = Some(word_list),
@ -86,21 +87,21 @@ fn load_word_list_with_exclusions(path: &PathBuf) -> (Vec<String>, Vec<String>)
let mut words = Vec::new();
for line in lines {
if line.starts_with('!') {
// Remove the '!' prefix and add to exclusions
exclusions.push(line[1..].to_string());
if let Some(stripped_line) = line.strip_prefix('!') {
exclusions.push(stripped_line.to_string());
} else {
words.push(line);
}
}
// Filter out any words that are in the exclusion list
let filtered_words = words.into_iter()
let filtered_words = words
.into_iter()
.filter(|word| !exclusions.contains(word))
.collect();
(filtered_words, exclusions)
},
}
Err(_) => (Vec::new(), Vec::new()),
}
}
@ -122,7 +123,7 @@ fn expand_env_vars(text: &str) -> String {
Some(v) => v.as_str(),
None => return "".to_string(),
};
env::var(var_name).unwrap_or_else(|_| format!("${{{}}}", var_name))
env::var(var_name).unwrap_or_else(|_| format!("${{{var_name}}}"))
})
.to_string()
}
@ -150,10 +151,10 @@ fn execute_bash_command(command: &str) -> String {
if output.status.success() {
String::from_utf8_lossy(&output.stdout).trim().to_string()
} else {
format!("$({})", command)
format!("$({command})")
}
}
Err(_) => format!("$({})", command),
Err(_) => format!("$({command})"),
}
}
@ -175,7 +176,7 @@ fn is_recursive_command(command: &str) -> bool {
return true;
}
if let Some(command_name) = token.split('/').last() {
if let Some(command_name) = token.split('/').next_back() {
if command_name == program_name {
return true;
}
@ -191,16 +192,22 @@ pub fn load_rc_file() -> RcArgs {
for path in rc_locations {
if path.exists() {
match fs::read_to_string(&path) {
Ok(content) => {
match toml::from_str::<RcArgs>(&content) {
Ok(rc_args) => return rc_args,
Err(e) => {
eprintln!("Warning: Failed to parse RC file '{}': {}", path.display(), e);
}
Ok(content) => match toml::from_str::<RcArgs>(&content) {
Ok(rc_args) => return rc_args,
Err(e) => {
eprintln!(
"Warning: Failed to parse RC file '{}': {}",
path.display(),
e
);
}
}
},
Err(e) => {
eprintln!("Warning: Failed to read RC file '{}': {}", path.display(), e);
eprintln!(
"Warning: Failed to read RC file '{}': {}",
path.display(),
e
);
}
}
}
@ -227,7 +234,12 @@ fn get_rc_locations() -> Vec<PathBuf> {
locations.push(PathBuf::from(xdg_config).join("motd").join("motdrc"));
} else if let Ok(home) = env::var("HOME") {
// Fallback to ~/.config/motd/motdrc if XDG_CONFIG_HOME is not set
locations.push(PathBuf::from(home).join(".config").join("motd").join("motdrc"));
locations.push(
PathBuf::from(home)
.join(".config")
.join("motd")
.join("motdrc"),
);
}
locations

View File

@ -27,8 +27,7 @@ impl fmt::Display for GeneratorError {
),
GeneratorError::CutOffExceeded { attempts, cut_off } => write!(
f,
"Could not generate a message within {} characters after {} attempts.",
cut_off, attempts
"Could not generate a message within {cut_off} characters after {attempts} attempts.",
),
}
}
@ -56,7 +55,7 @@ pub fn generate_message(arg_words: WordList, args: Args) -> Result<String, Gener
};
// Build word lists once
let word_lists: HashMap<WordType, Vec<String>> = WORD_TYPES
let word_lists: HashMap<WordType, Vec<String>> = WORD_TYPES
.iter()
.filter(|&word_type| *word_type != WordType::Template)
.map(|&word_type| {
@ -95,7 +94,13 @@ pub fn generate_message(arg_words: WordList, args: Args) -> Result<String, Gener
};
(
word_type,
build_word_list(defaults, config_words, custom_words, exclusions, args.replace),
build_word_list(
defaults,
config_words,
custom_words,
exclusions,
args.replace,
),
)
})
.collect();
@ -155,7 +160,7 @@ pub fn generate_message(arg_words: WordList, args: Args) -> Result<String, Gener
if attempts >= MAX_CUTOFF_ATTEMPTS {
return Err(GeneratorError::CutOffExceeded {
attempts,
cut_off: cut_off_len
cut_off: cut_off_len,
});
}

View File

@ -36,38 +36,37 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
match word_type.to_lowercase().as_str() {
"adjectives" | "adjective" => {
for adj in adjectives::ADJECTIVES {
println!("{}", adj);
println!("{adj}");
}
}
"nouns" | "noun" => {
for noun in nouns::NOUNS {
println!("{}", noun);
println!("{noun}");
}
}
"verbs" | "verb" => {
for verb in verbs::VERBS {
println!("{}", verb);
println!("{verb}");
}
}
"adverbs" | "adverb" => {
for adverb in adverbs::ADVERBS {
println!("{}", adverb);
println!("{adverb}");
}
}
"locations" | "location" => {
for location in locations::LOCATIONS {
println!("{}", location);
println!("{location}");
}
}
"templates" | "template" => {
for template in TEMPLATES {
println!("{}", template);
println!("{template}");
}
}
_ => {
eprintln!(
"Unknown word type: {}. Valid types are: adjectives, nouns, verbs, adverbs, locations, templates",
word_type
"Unknown word type: {word_type}. Valid types are: adjectives, nouns, verbs, adverbs, locations, templates",
);
std::process::exit(1);
}
@ -104,13 +103,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let message = generate_message(word_list, args)?;
match output {
Some(output_path) => {
std::fs::write(&output_path, format!("{}\n", message)).unwrap_or_else(|e| {
eprintln!("Failed to write to file '{}': {}", output_path, e);
std::fs::write(&output_path, format!("{message}\n")).unwrap_or_else(|e| {
eprintln!("Failed to write to file '{output_path}': {e}");
std::process::exit(1);
});
}
None => {
println!("{}", message);
println!("{message}");
}
}

View File

@ -49,11 +49,11 @@ pub fn capitalize_sentences(text: &str, uppercase: bool, lowercase: bool) -> Str
if capitalize_next && ch.is_alphabetic() {
result.push(ch.to_uppercase().next().unwrap_or(ch));
capitalize_next = false;
} else if matches!(ch, ' ') {
result.push(ch);
} else {
result.push(ch);
if matches!(ch, '.' | '!' | '?') {
capitalize_next = true;
}
capitalize_next = matches!(ch, '.' | '!' | '?');
}
}
}