typos_git_commit/
thashmap.rs1use crate::cli::{Cli, TypoType};
2use crate::keyvalue::{Key, Value};
3use crate::typosjsonline::TyposJsonLine;
4use fluent_i18n::t;
5use std::collections::HashMap;
6use std::error::Error;
7use std::fs::File;
8use std::io::{self, BufRead};
9use std::path::Path;
10use std::process::exit;
11
12#[derive(Debug)]
16pub struct THashMap {
17 hashmap: HashMap<Key, Vec<Value>>,
18}
19
20impl Default for THashMap {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl THashMap {
27 fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
28 where
29 P: AsRef<Path>,
30 {
31 let file = File::open(filename)?;
32 Ok(io::BufReader::new(file).lines())
33 }
34
35 #[must_use]
36 pub fn new() -> Self {
37 let hashmap: HashMap<Key, Vec<Value>> = HashMap::new();
38 THashMap {
39 hashmap,
40 }
41 }
42
43 pub fn insert(&mut self, typojson: TyposJsonLine, cli: &Cli) {
46 if !typojson.is_excluded(cli) {
47 let typo = typojson.typo;
48 let corrections = typojson.corrections;
49 let key = Key {
50 typo,
51 corrections,
52 };
53
54 if let Some(v) = self.hashmap.get_mut(&key) {
55 let value = Value {
58 path: typojson.path,
59 line_num: typojson.line_num,
60 byte_offset: typojson.byte_offset,
61 };
62 v.push(value);
63 } else {
64 let mut v: Vec<Value> = Vec::new();
67 let value = Value {
68 path: typojson.path,
69 line_num: typojson.line_num,
70 byte_offset: typojson.byte_offset,
71 };
72 v.push(value);
73 self.hashmap.insert(key, v);
74 }
75 } else if cli.debug {
76 if typojson.is_file_excluded(cli) {
79 eprintln!("{}", t!("thashmap-file-excluded", {"file" => typojson.path}));
80 } else if typojson.is_typo_excluded(cli) {
81 eprintln!("{}", t!("thashmap-typo-excluded", {"typo" => typojson.typo}));
82 } else if typojson.is_correction_excluded(cli) {
83 eprintln!(
84 "{}",
85 t!("thashmap-correction-excluded", { "correction" => format!("{:?}", typojson.corrections), "typo" => typojson.typo})
86 );
87 }
88 }
89 }
90
91 pub fn read_typos_file(mut self, cli: &Cli) -> Result<Self, Box<dyn Error>> {
97 match THashMap::read_lines(&cli.filename) {
98 Ok(lines) => {
99 for line in lines.map_while(Result::ok) {
101 let typojson = serde_json::from_str::<TyposJsonLine>(&line)?;
102 if typojson.type_id == "typo" {
103 self.insert(typojson, cli);
104 }
105 }
106 }
107 Err(e) => {
108 eprintln!("{}", t!("thashmap-error-file", {"e" => e.to_string()}));
109 exit(1);
110 }
111 }
112 Ok(self)
113 }
114
115 pub fn list_typos(&self, cli: &Cli) {
117 let Some(only_list_typos) = &cli.only_list_typos else {
118 return;
119 };
120
121 for (key, values) in &self.hashmap {
122 let files_string = t!("thashmap-file-count", {"count" => values.len()}).to_string();
123
124 let correctable = key.is_typo_correctable(cli);
128
129 let should_print = matches!(
130 (correctable, only_list_typos),
131 (true, TypoType::All | TypoType::Corrected) | (false, TypoType::All | TypoType::NotCorrected)
132 );
133
134 if !should_print {
135 continue;
136 }
137
138 if correctable {
139 println!("'{}' -> {:?}) {}", key.typo, key.corrections, files_string);
140 } else {
141 println!(
142 "\t{}",
143 t!("thashmap-wont-correct", {"typo" => key.typo, "correction" => format!("{:?}",key.corrections), "files" => files_string})
144 );
145 }
146
147 if cli.details {
148 for v in values {
149 v.print_value_details();
150 }
151 println!();
152 }
153 }
154 }
155
156 pub fn correct_typos(&self, cli: &Cli) {
158 for (key, values) in &self.hashmap {
159 if key.is_typo_correctable(cli) {
163 let files = values.iter().map(|v| v.path.clone()).collect();
164
165 key.run_sed(&files, cli);
166 key.run_git_commit(cli);
167 } else if cli.details {
168 println!();
169 println!(
170 "{}\n{}",
171 t!("thashmap-typo-not-corrected", {"typo" => key.typo, "correction" => format!("{:?}",key.corrections)}),
172 t!("thashmap-typo-look-carefully")
173 );
174 for v in values {
175 v.print_value_details();
176 }
177 println!();
178 }
179 }
180 }
181}