terminal_dictionary/
lib.rs

1use colored::Colorize;
2use clap::{command, Arg, Command};
3use serde::Deserialize;
4// use serde_json;
5
6#[derive(Debug)]
7// This enum tells the main function which 
8// print method (dictionary or thesaurus) needs to be used
9// get_config returns this
10pub enum QueryType{
11    Dictionary(String),
12    Thesaurus(String),
13}
14
15impl QueryType{
16    pub fn new()-> Result<QueryType, Box<dyn std::error::Error>>{
17        let matches = command!()
18        .about("Simple Dictionary on the terminal.")
19        .version("0.1.0")
20        .author("Axolotl rishavghosh2007@gmail.com")
21        .subcommand(
22            Command::new("def")
23            .about("search dictionary")
24            .arg(
25                Arg::new("def_word")
26                .help("word to search in dictionary")
27                .required(true)
28                .index(1)
29            )
30        )
31        .subcommand(
32            Command::new("thes")
33            .about("search thesaurus")
34            .arg(
35                Arg::new("thes_word")
36                .help("word to search in thesaurus")
37                .required(true)
38                .index(1)
39            )
40        ).get_matches();
41    
42        let query_type: QueryType;
43    
44    
45        if let Some(def_matches) = matches.subcommand_matches("def") {
46            if let Some(def_word) = def_matches.get_one::<String>("def_word") {
47                query_type = QueryType::Dictionary(def_word.to_string());
48            } else {
49                return Err("Invalid word entered for `def`".into());
50            }
51        } else if let Some(thes_matches) = matches.subcommand_matches("thes") {
52            if let Some(thes_word) = thes_matches.get_one::<String>("thes_word") {
53                query_type = QueryType::Thesaurus(thes_word.to_string());
54            } else {
55                return Err("Invalid word entered for `thes`".into());
56            }
57        } else {
58            return Err("No subcommand was used".into());
59        }
60        Ok(query_type)
61    }
62}
63// these are the structs the api response deserializes into
64// '->' means 'contains'
65// Wordinfo -> Singlemeaning -> Definition
66#[derive(Debug, Deserialize, Clone)]
67pub struct WordInfo{
68    word: String,
69    meanings: Vec<SingleMeaning>,
70}
71
72impl WordInfo{
73    pub fn dictionary(&self){
74        for meaning in self.meanings.iter(){
75            println!("{}-----------{}", self.word.to_uppercase().green().bold(), meaning.part_of_speech.to_ascii_uppercase().italic().green());
76            for def_obj in meaning.definitions.iter(){
77                println!("{}", def_obj.definition.bold());
78                println!("Example: {}\n", def_obj.example.clone().unwrap_or("N/A".to_string()).blue().italic());
79            }
80        }
81    }
82
83    pub fn thesaurus(&self){
84        let mut syn_list: String = String::new();
85        let mut ant_list: String = String::new();
86    
87        for meaning in self.meanings.iter(){
88            for syn in meaning.synonyms.iter(){
89                syn_list.push_str(format!("{}, ", syn).as_str());
90            }
91    
92            for ant in meaning.antonyms.iter(){
93                ant_list.push_str(format!("{}, ", ant).as_str());
94            }
95        }
96    
97        println!("Synonyms and antonyms for {}", self.word.to_uppercase().bold().italic().green());
98        println!("Synonyms: {}", syn_list.bold());
99        println!("Antonyms: {}", ant_list.bold());
100    }
101}
102
103#[derive(Debug, Deserialize, Clone)]
104pub struct SingleMeaning{
105    #[serde(rename = "partOfSpeech")]
106    part_of_speech: String,
107    definitions: Vec<Definition>,
108    synonyms: Vec<String>,
109    antonyms: Vec<String>,
110}
111
112#[derive(Debug, Deserialize, Clone)]
113pub struct Definition{
114    definition: String,
115    example: Option<String>,
116}
117
118pub fn get_json(search_word: &String) -> Result<WordInfo, Box<dyn std::error::Error>>{
119    let url: String = format!("https://api.dictionaryapi.dev/api/v2/entries/en/{}", search_word);
120
121    let res = ureq::get(&url).call()?.into_string()?;
122
123    let word_info: Vec<WordInfo> = serde_json::from_str(&res)?;
124
125    Ok(word_info.first().unwrap().clone())
126}