diff --git a/src/kanji_search.rs b/src/kanji_search.rs index 6da2ef6..51c30ae 100644 --- a/src/kanji_search.rs +++ b/src/kanji_search.rs @@ -6,143 +6,150 @@ use std::{ use kradical_parsing::radk; -pub fn search_by_radical(query: &mut String, radk_list: &[radk::Membership], stroke_info: &[HashSet]) -> Option<()> { - let mut result: HashSet<_> = HashSet::new(); - let mut aux: HashSet<_> = HashSet::new(); - - if !radk_list.is_empty() && !stroke_info.is_empty() { - result.clear(); - - /* First iteration: get the baseline for the results */ - let mut rad = query.chars().nth(1).unwrap(); - if rad == '*' || rad == '*' { - /* if search_by_strokes failed, then something is very wrong */ - rad = search_by_strokes(query, radk_list, 1)?; - } - - for k in radk_list.iter() { - if k.radical.glyph.contains(rad) { - for input in &k.kanji { - result.insert(input); - } - break; +pub fn search_by_radical<'a>(query: &mut String, radk_list: *const Vec, stroke_info: &[HashSet], result: &mut HashSet<&'a String>, aux: &mut HashSet<&'a String>, vec: &mut Vec>) -> Option<()> { + //let mut result: HashSet<_> = HashSet::new(); + //let mut aux: HashSet<_> = HashSet::new(); + unsafe { + if !(*radk_list).is_empty() && !stroke_info.is_empty() { + result.clear(); + for i in 0..30 { + vec[i].clear(); } - } - /* Iterate until you've exhausted user input: refine the baseline to get final output */ - for (i, mut rad) in query.clone().chars().skip(2).enumerate() { + /* First iteration: get the baseline for the results */ + let mut rad = query.chars().nth(1).unwrap(); if rad == '*' || rad == '*' { /* if search_by_strokes failed, then something is very wrong */ - rad = search_by_strokes(query, radk_list, i+2)?; + rad = search_by_strokes(query, radk_list, 1)?; } - for k in radk_list.iter() { + for k in (*radk_list).iter() { if k.radical.glyph.contains(rad) { for input in &k.kanji { - aux.insert(input); + result.insert(input); } - result = &result & &aux; - aux.clear(); break; } } - } - /* Hash sets are unordered; Will now order the results by number of strokes */ - let mut vec: Vec> = Vec::with_capacity(30); /* The kanji we care about will have at most 30 strokes */ - for _i in 0..29 { - vec.push(Vec::new()); - } + /* Iterate until you've exhausted user input: refine the baseline to get final output */ + for (i, mut rad) in query.clone().chars().skip(2).enumerate() { + if rad == '*' || rad == '*' { + /* if search_by_strokes failed, then something is very wrong */ + rad = search_by_strokes(query, radk_list, i+2)?; + } - /* - * A vector of vectors is useful here to store kanji by number of strokes - * First vector's index will indicate the number of strokes (minus 1 because it starts at 0) - * Second vector will hold all of the kanji that is written in that number of strokes - */ - for r in &result { - for (i, s) in stroke_info.iter().enumerate() { - if s.contains(&(r.chars().next().unwrap())) { /* r is a String that has just one character */ - vec[i].push(r); - break; + for k in (*radk_list).iter() { + if k.radical.glyph.contains(rad) { + for input in &k.kanji { + aux.insert(input); + } + *result = &*result & &*aux; + aux.clear(); + break; + } } } - } - for (i, v) in vec.iter().enumerate() { - if !v.is_empty() { - let ii = i + 1; - print!("\x1b[90m{:02} -\x1b[m", ii); - for l in v { - print!(" {l}"); + /* Hash sets are unordered; Will now order the results by number of strokes */ + //let mut vec: Vec> = Vec::with_capacity(30); /* The kanji we care about will have at most 30 strokes */ + //for _i in 0..30 { + // vec.push(Vec::new()); + //} + + /* + * A vector of vectors is useful here to store kanji by number of strokes + * First vector's index will indicate the number of strokes (minus 1 because it starts at 0) + * Second vector will hold all of the kanji that is written in that number of strokes + */ + for r in result.iter() { + for (i, s) in stroke_info.iter().enumerate() { + if s.contains(&(r.chars().next().unwrap())) { /* r is a String that has just one character */ + vec[i].push(r); + break; + } } - println!(); } + + for (i, v) in vec.iter().enumerate() { + if !v.is_empty() { + let ii = i + 1; + print!("\x1b[90m{:02} -\x1b[m", ii); + for l in v { + print!(" {l}"); + } + println!(); + } + } + } else if (*radk_list).is_empty() { + eprintln!("Error while reading radkfile\nIf you don't have the radkfile, download it from\n\ + https://www.edrdg.org/krad/kradinf.html and place it in \"~/.local/share/\" on Linux or \"~\\AppData\\Local\\\" on Windows.\n\ + This file is needed to search radicals by strokes."); + } else { + eprintln!("File \"/usr/local/share/ykdt/kanji_strokes\" is missing!"); } - } else if radk_list.is_empty() { - eprintln!("Error while reading radkfile\nIf you don't have the radkfile, download it from\n\ - https://www.edrdg.org/krad/kradinf.html and place it in \"~/.local/share/\" on Linux or \"~\\AppData\\Local\\\" on Windows.\n\ - This file is needed to search radicals by strokes."); - } else { - eprintln!("File \"/usr/local/share/ykdt/kanji_strokes\" is missing!"); } Some(()) } -fn search_by_strokes(query: &mut String, radk_list: &[radk::Membership], n: usize) -> Option { +fn search_by_strokes(query: &mut String, radk_list: *const Vec, n: usize) -> Option { let mut strokes = String::new(); let mut radicals: Vec = Vec::new(); let rad; - loop{ - print!("How many strokes does your radical have? "); - stdout().flush().ok()?; - strokes.clear(); - if stdin().read_line(&mut strokes).ok()? == 0{ - std::process::exit(0); - } - match strokes.trim().parse::() { - Ok(strk) => { - let mut i = 1; - for k in radk_list.iter() { - if k.radical.strokes == strk { - print!("{}{} ", i, k.radical.glyph); - radicals.push(k.radical.glyph.chars().next()?); - i += 1; - } else if k.radical.strokes > strk { - println!(); - break; - } - } - loop { - print!("Choose the radical to use for your search: "); - stdout().flush().ok()?; - strokes.clear(); - if stdin().read_line(&mut strokes).ok()? == 0{ - std::process::exit(0); - } + unsafe { + loop { + print!("How many strokes does your radical have? "); + stdout().flush().ok()?; + strokes.clear(); + if stdin().read_line(&mut strokes).ok()? == 0{ + std::process::exit(0); + } - match strokes.trim().parse::() { - Ok(strk) => { - if strk < 1 || strk > i-1 { - eprintln!("Couldn't parse input: number not in range"); - } else { - rad = radicals.get(strk-1)?; - /* UTF-8 is not fun */ - let char_and_index = query.char_indices().nth(n)?; - query.replace_range(char_and_index.0.. - char_and_index.0 + - char_and_index.1.len_utf8(), - rad.to_string().as_str()); - println!("\x1b[90m{}\x1b[m", query); - return Some(*rad); - } - }, - Err(e) => { eprintln!("{e}"); } + match strokes.trim().parse::() { + Ok(strk) => { + let mut i = 1; + for k in (*radk_list).iter() { + if k.radical.strokes == strk { + print!("{}{} ", i, k.radical.glyph); + radicals.push(k.radical.glyph.chars().next()?); + i += 1; + } else if k.radical.strokes > strk { + println!(); + break; + } } - } - }, - Err(e) => { eprintln!("{e}") } + loop { + print!("Choose the radical to use for your search: "); + stdout().flush().ok()?; + strokes.clear(); + if stdin().read_line(&mut strokes).ok()? == 0{ + std::process::exit(0); + } + + match strokes.trim().parse::() { + Ok(strk) => { + if strk < 1 || strk > i-1 { + eprintln!("Couldn't parse input: number not in range"); + } else { + rad = radicals.get(strk-1)?; + /* UTF-8 is not fun */ + let char_and_index = query.char_indices().nth(n)?; + query.replace_range(char_and_index.0.. + char_and_index.0 + + char_and_index.1.len_utf8(), + rad.to_string().as_str()); + println!("\x1b[90m{}\x1b[m", query); + return Some(*rad); + } + }, + Err(e) => { eprintln!("{e}"); } + } + } + }, + Err(e) => { eprintln!("{e}") } + } } } } diff --git a/src/main.rs b/src/main.rs index e01f340..c2b3ef7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,9 @@ use std::{ io::{stdin, stdout, Write, IsTerminal}, path::PathBuf, process::{Command, Stdio}, + cell::RefCell, env, + collections::HashSet, }; use word_search::word_search; @@ -42,10 +44,18 @@ fn main() -> Result<(), ureq::Error> { }; let path = get_radkfile_path().unwrap(); - let mut radk_list = Vec::new(); + //let mut radk_list = Vec::new(); + let radk_list = RefCell::new(Vec::new()); let mut stroke_info = Vec::new(); let mut try_load = true; + let mut result: HashSet<&String> = HashSet::new(); + let mut aux: HashSet<&String> = HashSet::new(); + let mut vec: Vec> = Vec::with_capacity(30); /* The kanji we care about will have at most 30 strokes */ + for _i in 0..30 { + vec.push(Vec::new()); + } + let options = parse_args(); @@ -74,10 +84,9 @@ fn main() -> Result<(), ureq::Error> { if query.starts_with(':') || query.starts_with(':') { /* Kanji search */ if try_load { - radk_list = { match radk::parse_file(&path) { - Ok(radk_list) => radk_list, - Err(_e) => radk_list, - } + match radk::parse_file(&path) { + Ok(list) => { radk_list.replace(list); }, + Err(_e) => () }; stroke_info = { match get_stroke_info() { Ok(stroke_info) => stroke_info, @@ -87,10 +96,9 @@ fn main() -> Result<(), ureq::Error> { try_load = false; } /* if search_by_radical failed, then something is very wrong */ - if search_by_radical(&mut query, &radk_list, &stroke_info).is_none() { + if search_by_radical(&mut query, radk_list.as_ptr(), &stroke_info, &mut result, &mut aux, &mut vec).is_none() { eprintln!("Couldn't parse input"); } - } else if query.starts_with('_') || query.starts_with('_') { /* Sentence search */ let bytes = query.chars().next().unwrap().len_utf8();