Removed unnecessary mallocs.
The colored crate was being used for convinient coloring of the terminal text, but after profiling I found it was responsible for almost 1/3 of the memory allocations of the jisho searching feature. Decided to write ANSI codes manually instead, along with using write! + format_args! instead of format! for similar reasons, but not as egregious.
This commit is contained in:
parent
a475790e63
commit
6fcd5489d5
5 changed files with 73 additions and 70 deletions
|
@ -21,7 +21,6 @@ libc = "0.2.151"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ureq = { version = "2.8.0", features = ["json"] }
|
ureq = { version = "2.8.0", features = ["json"] }
|
||||||
serde_json = "1.0.108"
|
serde_json = "1.0.108"
|
||||||
colored = "2.1.0"
|
|
||||||
argparse = "0.2.2"
|
argparse = "0.2.2"
|
||||||
atty = "0.2.14"
|
atty = "0.2.14"
|
||||||
kradical_parsing = "0.1.0"
|
kradical_parsing = "0.1.0"
|
||||||
|
|
|
@ -3,7 +3,6 @@ use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
use colored::*;
|
|
||||||
use kradical_parsing::radk;
|
use kradical_parsing::radk;
|
||||||
|
|
||||||
pub fn search_by_radical(query: &mut String, radk_list: &[radk::Membership]) -> Option<()> {
|
pub fn search_by_radical(query: &mut String, radk_list: &[radk::Membership]) -> Option<()> {
|
||||||
|
@ -105,7 +104,7 @@ fn search_by_strokes(query: &mut String, radk_list: &[radk::Membership], n: usiz
|
||||||
char_and_index.0 +
|
char_and_index.0 +
|
||||||
char_and_index.1.len_utf8(),
|
char_and_index.1.len_utf8(),
|
||||||
rad.to_string().as_str());
|
rad.to_string().as_str());
|
||||||
println!("{}", query.as_str().bright_black());
|
println!("\x1b[90m{}\x1b[m", query);
|
||||||
return Some(*rad);
|
return Some(*rad);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -48,7 +48,7 @@ fn main() -> Result<(), ureq::Error> {
|
||||||
|
|
||||||
let options = parse_args();
|
let options = parse_args();
|
||||||
|
|
||||||
let mut output = String::with_capacity(51200); /* Give output 50KiB of buffer; Should be enough to avoid reallocs*/
|
let mut output = String::with_capacity(3096); /* Give output 3KiB of buffer; Should be enough to avoid reallocs*/
|
||||||
let mut query = options.query.trim().to_string().clone();
|
let mut query = options.query.trim().to_string().clone();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
use std::fmt::Write;
|
||||||
use crate::util::*;
|
use crate::util::*;
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use colored::*;
|
|
||||||
|
|
||||||
pub fn sentence_search(options: &Options, body: Value, output: &mut String) -> Option<usize>{
|
pub fn sentence_search(options: &Options, body: Value, output: &mut String) -> Option<usize>{
|
||||||
|
|
||||||
|
@ -33,13 +33,12 @@ pub fn sentence_search(options: &Options, body: Value, output: &mut String) -> O
|
||||||
|
|
||||||
|
|
||||||
for translation in translations.iter() {
|
for translation in translations.iter() {
|
||||||
let index_str = format!("{}.", i).bright_black();
|
|
||||||
|
|
||||||
/* Prefer to keep japanese sentences on top */
|
/* Prefer to keep japanese sentences on top */
|
||||||
if entry.get("lang")? == "eng" {
|
if entry.get("lang")? == "eng" {
|
||||||
*output += &format!("{} {}\n {}\n\n", index_str, value_to_str(translation.get("text")?), value_to_str(entry.get("text")?));
|
write!(output, "{}", format_args!("\x1b[90m{}.\x1b[m {}\n {}\n\n", i, value_to_str(translation.get("text")?), value_to_str(entry.get("text")?))).unwrap();
|
||||||
} else {
|
} else {
|
||||||
*output += &format!("{} {}\n {}\n\n", index_str, value_to_str(entry.get("text")?), value_to_str(translation.get("text")?));
|
write!(output, "{}", format_args!("\x1b[90m{}.\x1b[m {}\n {}\n\n", i, value_to_str(entry.get("text")?), value_to_str(translation.get("text")?))).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
use std::fmt::Write;
|
||||||
use crate::util::*;
|
use crate::util::*;
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use colored::*;
|
|
||||||
|
|
||||||
pub fn word_search(options: &Options, body: Value, query: &str, output: &mut String) -> Option<usize> {
|
pub fn word_search(options: &Options, body: Value, query: &str, output: &mut String) -> Option<usize> {
|
||||||
let mut lines_output = 0;
|
let mut lines_output = 0;
|
||||||
|
@ -36,46 +36,49 @@ fn print_item(query: &str, value: &Value, output: &mut String) -> Option<usize>
|
||||||
let main_form = japanese.get(0)?;
|
let main_form = japanese.get(0)?;
|
||||||
let mut num_of_lines = 0;
|
let mut num_of_lines = 0;
|
||||||
|
|
||||||
*output += &format!("{} {}\n", format_form(query, main_form)?, format_result_tags(value));
|
format_form(query, main_form, output)?;
|
||||||
|
format_result_tags(value, output);
|
||||||
|
output.push('\n');
|
||||||
|
|
||||||
/* Print senses */
|
/* Print senses */
|
||||||
let senses = value_to_arr(value.get("senses")?);
|
let senses = value_to_arr(value.get("senses")?);
|
||||||
let mut prev_parts_of_speech = String::new();
|
let mut prev_parts_of_speech = String::new();
|
||||||
|
|
||||||
for (i, sense) in senses.iter().enumerate() {
|
for (i, sense) in senses.iter().enumerate() {
|
||||||
let (sense_str, new_part_of_speech) = format_sense(sense, i, &mut prev_parts_of_speech);
|
let new_part_of_speech = format_sense(sense, i+1, output, &mut prev_parts_of_speech);
|
||||||
if !sense_str.is_empty() {
|
/*
|
||||||
/*
|
* If the current meaning of our word is a different part of speech
|
||||||
* If the current meaning of our word is a different part of speech
|
* (e.g. previous meaning was 'Noun' and the current is 'Adverb'), an extra line will be
|
||||||
* (e.g. previous meaning was 'Noun' and the current is 'Adverb'), an extra line will be
|
* printed with this information
|
||||||
* printed with this information
|
*/
|
||||||
*/
|
if new_part_of_speech {
|
||||||
if new_part_of_speech {
|
num_of_lines += 1;
|
||||||
num_of_lines += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*output += &format!(" {}\n", sense_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print alternative readings and kanji usage */
|
/* Print alternative readings and kanji usage */
|
||||||
if let Some(form) = japanese.get(1) {
|
if let Some(form) = japanese.get(1) {
|
||||||
num_of_lines += 2;
|
num_of_lines += 2;
|
||||||
|
|
||||||
*output += &format!(" {}", "Other forms\n".bright_blue());
|
output.push_str(" \x1b[94mOther forms\x1b[m\n ");
|
||||||
*output += &format!(" {}", format_form(query, form)?);
|
format_form(query, form, output)?;
|
||||||
|
|
||||||
for i in 2..japanese.len() {
|
for i in 2..japanese.len() {
|
||||||
*output += &format!(", {}", format_form(query, japanese.get(i)?)?);
|
output.push_str(", ");
|
||||||
|
format_form(query, japanese.get(i)?, output)?;
|
||||||
}
|
}
|
||||||
output.push('\n');
|
output.push('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear any font effect or colour */
|
||||||
|
output.push_str("\x1b[m");
|
||||||
|
|
||||||
num_of_lines += senses.len() + 1;
|
num_of_lines += senses.len() + 1;
|
||||||
Some(num_of_lines)
|
Some(num_of_lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_form(query: &str, form: &Value) -> Option<String> {
|
fn format_form(query: &str, form: &Value, output: &mut String) -> Option<()> {
|
||||||
let reading = form
|
let reading = form
|
||||||
.get("reading")
|
.get("reading")
|
||||||
.map(value_to_str)
|
.map(value_to_str)
|
||||||
|
@ -83,19 +86,22 @@ fn format_form(query: &str, form: &Value) -> Option<String> {
|
||||||
|
|
||||||
let word = value_to_str(form.get("word").unwrap_or(form.get("reading")?));
|
let word = value_to_str(form.get("word").unwrap_or(form.get("reading")?));
|
||||||
|
|
||||||
Some(format!("{}[{}]", word, reading))
|
write!(output, "{}", format_args!("{}[{}]", word, reading)).ok()?;
|
||||||
|
|
||||||
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_sense(value: &Value, index: usize, prev_parts_of_speech: &mut String) -> (String, bool) {
|
fn format_sense(value: &Value, index: usize, output: &mut String, prev_parts_of_speech: &mut String) -> bool {
|
||||||
let english_definitons = value.get("english_definitions");
|
let english_definitons = value.get("english_definitions");
|
||||||
let parts_of_speech = value.get("parts_of_speech");
|
let parts_of_speech = value.get("parts_of_speech");
|
||||||
if english_definitons.is_none() {
|
if english_definitons.is_none() {
|
||||||
return ("".to_owned(), false);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let english_definiton = value_to_arr(english_definitons.unwrap());
|
let english_definiton = value_to_arr(english_definitons.unwrap());
|
||||||
|
|
||||||
let parts_of_speech = if let Some(parts_of_speech) = parts_of_speech {
|
let is_part_of_speech_new;
|
||||||
|
if let Some(parts_of_speech) = parts_of_speech {
|
||||||
let parts = value_to_arr(parts_of_speech)
|
let parts = value_to_arr(parts_of_speech)
|
||||||
.iter()
|
.iter()
|
||||||
.map(value_to_str)
|
.map(value_to_str)
|
||||||
|
@ -105,45 +111,40 @@ fn format_sense(value: &Value, index: usize, prev_parts_of_speech: &mut String)
|
||||||
/* Do not repeat a meaning's part of speech if it is the same as the previous meaning */
|
/* Do not repeat a meaning's part of speech if it is the same as the previous meaning */
|
||||||
if !parts.is_empty() && parts != *prev_parts_of_speech {
|
if !parts.is_empty() && parts != *prev_parts_of_speech {
|
||||||
*prev_parts_of_speech = parts.clone();
|
*prev_parts_of_speech = parts.clone();
|
||||||
format!("{}\n ", parts.bright_blue())
|
is_part_of_speech_new = true;
|
||||||
|
|
||||||
|
write!(output, "{}", format_args!(" \x1b[34m{}\x1b[m\n", parts)).unwrap();
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
is_part_of_speech_new = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
is_part_of_speech_new = false;
|
||||||
};
|
|
||||||
|
|
||||||
let new_part_of_speech = !parts_of_speech.is_empty();
|
|
||||||
|
|
||||||
let index_str = format!("{}.",(index + 1));
|
|
||||||
let mut tags = format_sense_tags(value);
|
|
||||||
let info = format_sense_info(value);
|
|
||||||
|
|
||||||
if !info.is_empty() && !tags.is_empty() {
|
|
||||||
tags.push(',');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(format!(
|
write!(output, "{}",
|
||||||
"{}{} {}{}{}",
|
format_args!(" \x1b[90m{}.\x1b[m {}",
|
||||||
parts_of_speech,
|
index,
|
||||||
index_str.bright_black(),
|
|
||||||
english_definiton
|
english_definiton
|
||||||
.iter()
|
.iter()
|
||||||
.map(value_to_str)
|
.map(value_to_str)
|
||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
.join(", "),
|
.join(", "),
|
||||||
tags.bright_black(),
|
)).unwrap();
|
||||||
info.bright_black(),
|
|
||||||
), new_part_of_speech)
|
let t = format_sense_tags(value, output);
|
||||||
|
format_sense_info(value, output, t);
|
||||||
|
output.push('\n');
|
||||||
|
|
||||||
|
|
||||||
|
return is_part_of_speech_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format tags from a whole meaning
|
/// Format tags from a whole meaning
|
||||||
fn format_result_tags(value: &Value) -> String {
|
fn format_result_tags(value: &Value, output: &mut String) {
|
||||||
let mut builder = String::new();
|
|
||||||
|
|
||||||
let is_common_val = value.get("is_common");
|
let is_common_val = value.get("is_common");
|
||||||
if is_common_val.is_some() && value_to_bool(is_common_val.unwrap()) {
|
if is_common_val.is_some() && value_to_bool(is_common_val.unwrap()) {
|
||||||
builder.push_str(&"(common) ".bright_green().to_string());
|
output.push_str("\x1b[92m(common)\x1b[m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(jlpt) = value.get("jlpt") {
|
if let Some(jlpt) = value.get("jlpt") {
|
||||||
|
@ -156,52 +157,57 @@ fn format_result_tags(value: &Value) -> String {
|
||||||
let jlpt = value_to_str(jlpt.get(0).unwrap())
|
let jlpt = value_to_str(jlpt.get(0).unwrap())
|
||||||
.replace("jlpt-", "")
|
.replace("jlpt-", "")
|
||||||
.to_uppercase();
|
.to_uppercase();
|
||||||
builder.push_str(&format!("({}) ", jlpt.bright_blue()));
|
write!(output, "{}", format_args!("\x1b[94m({})\x1b[m", jlpt)).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format tags from a single sense entry
|
/// Format tags from a single sense entry
|
||||||
fn format_sense_tags(value: &Value) -> String {
|
fn format_sense_tags(value: &Value, output: &mut String) -> bool {
|
||||||
let mut builder = String::new();
|
|
||||||
|
|
||||||
if let Some(tags) = value.get("tags") {
|
if let Some(tags) = value.get("tags") {
|
||||||
let tags = value_to_arr(tags);
|
let tags = value_to_arr(tags);
|
||||||
|
|
||||||
if let Some(tag) = tags.get(0) {
|
if let Some(tag) = tags.get(0) {
|
||||||
let t = format_sense_tag(value_to_str(tag));
|
let t = format_sense_tag(value_to_str(tag));
|
||||||
builder += &format!(" {}", t.as_str());
|
output.push_str(" \x1b[90m");
|
||||||
|
output.push_str(t);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for tag in tags.get(1).iter() {
|
for tag in tags.get(1).iter() {
|
||||||
let t = format_sense_tag(value_to_str(tag));
|
let t = format_sense_tag(value_to_str(tag));
|
||||||
builder += &format!(", {}", t.as_str());
|
output.push_str(", ");
|
||||||
|
output.push_str(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
builder
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_sense_tag(tag: &str) -> String {
|
fn format_sense_tag(tag: &str) -> &str{
|
||||||
match tag {
|
match tag {
|
||||||
"Usually written using kana alone" => "UK".to_string(),
|
"Usually written using kana alone" => "UK",
|
||||||
s => s.to_string(),
|
s => s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_sense_info(value: &Value) -> String {
|
fn format_sense_info(value: &Value, output: &mut String, t: bool) {
|
||||||
let mut builder = String::new();
|
|
||||||
if let Some(all_info) = value.get("info") {
|
if let Some(all_info) = value.get("info") {
|
||||||
let all_info = value_to_arr(all_info);
|
let all_info = value_to_arr(all_info);
|
||||||
|
|
||||||
if let Some(info) = all_info.get(0) {
|
if let Some(info) = all_info.get(0) {
|
||||||
builder += &format!(" {}", value_to_str(info));
|
if t {
|
||||||
|
output.push_str(",");
|
||||||
|
}
|
||||||
|
output.push_str(" \x1b[90m");
|
||||||
|
output.push_str(value_to_str(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
for info in all_info.get(1).iter() {
|
for info in all_info.get(1).iter() {
|
||||||
builder += &format!(", {}", value_to_str(info));
|
output.push_str(", ");
|
||||||
|
output.push_str(value_to_str(info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue