Merge branch 'master' into help-wanted-4-add-type-hints-5

This commit is contained in:
Damien Elmes 2020-07-29 13:56:57 +10:00 committed by GitHub
commit 6d0d210130
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 45 additions and 23 deletions

View File

@ -747,7 +747,7 @@ Enter deck to place new %s cards in, or leave blank:"""
try: try:
fut.result() fut.result()
except TemplateError as e: except TemplateError as e:
showWarning("Unable to save changes: " + str(e)) showWarning(str(e))
return return
self.mw.reset() self.mw.reset()
tooltip("Changes saved.", parent=self.parent()) tooltip("Changes saved.", parent=self.parent())

View File

@ -13,3 +13,6 @@ card-templates-preview-box = Preview
card-templates-template-box = Template card-templates-template-box = Template
card-templates-sample-cloze = This is a {"{{c1::"}sample{"}}"} cloze deletion. card-templates-sample-cloze = This is a {"{{c1::"}sample{"}}"} cloze deletion.
card-templates-fill-empty = Fill Empty Fields card-templates-fill-empty = Fill Empty Fields
card-templates-invalid-template-number = Please correct the problems on card template { $number } first.

View File

@ -146,6 +146,7 @@ fn anki_error_to_proto_error(err: AnkiError, i18n: &I18n) -> pb::BackendError {
AnkiError::Existing => V::Exists(Empty {}), AnkiError::Existing => V::Exists(Empty {}),
AnkiError::DeckIsFiltered => V::DeckIsFiltered(Empty {}), AnkiError::DeckIsFiltered => V::DeckIsFiltered(Empty {}),
AnkiError::SearchError(_) => V::InvalidInput(pb::Empty {}), AnkiError::SearchError(_) => V::InvalidInput(pb::Empty {}),
AnkiError::TemplateSaveError { .. } => V::TemplateParse(pb::Empty {}),
}; };
pb::BackendError { pb::BackendError {

View File

@ -93,15 +93,19 @@ pub fn reveal_cloze_text(text: &str, cloze_ord: u16, question: bool) -> Cow<str>
} }
pub fn reveal_cloze_text_only(text: &str, cloze_ord: u16, question: bool) -> Cow<str> { pub fn reveal_cloze_text_only(text: &str, cloze_ord: u16, question: bool) -> Cow<str> {
for caps in CLOZE.captures_iter(text) { CLOZE
let captured_ord = caps .captures_iter(text)
.get(cloze_caps::ORD) .filter(|caps| {
.unwrap() let captured_ord = caps
.as_str() .get(cloze_caps::ORD)
.parse() .unwrap()
.unwrap_or(0); .as_str()
.parse()
.unwrap_or(0);
if captured_ord == cloze_ord { captured_ord == cloze_ord
})
.map(|caps| {
let cloze = if question { let cloze = if question {
// hint provided? // hint provided?
if let Some(hint) = caps.get(cloze_caps::HINT) { if let Some(hint) = caps.get(cloze_caps::HINT) {
@ -112,11 +116,12 @@ pub fn reveal_cloze_text_only(text: &str, cloze_ord: u16, question: bool) -> Cow
} else { } else {
caps.get(cloze_caps::TEXT).unwrap().as_str() caps.get(cloze_caps::TEXT).unwrap().as_str()
}; };
return cloze.to_owned().into();
}
}
"".into() cloze
})
.collect::<Vec<_>>()
.join(", ")
.into()
} }
/// If text contains any LaTeX tags, render the front and back /// If text contains any LaTeX tags, render the front and back
@ -214,6 +219,10 @@ mod test {
); );
assert_eq!(reveal_cloze_text_only("foo {{c1::bar}}", 1, false), "bar"); assert_eq!(reveal_cloze_text_only("foo {{c1::bar}}", 1, false), "bar");
assert_eq!(reveal_cloze_text_only("foo {{c1::bar}}", 2, false), ""); assert_eq!(reveal_cloze_text_only("foo {{c1::bar}}", 2, false), "");
assert_eq!(
reveal_cloze_text_only("{{c1::foo}} {{c1::bar}}", 1, false),
"foo, bar"
);
} }
#[test] #[test]

View File

@ -1,7 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::i18n::{tr_strs, I18n, TR}; use crate::i18n::{tr_args, tr_strs, I18n, TR};
pub use failure::{Error, Fail}; pub use failure::{Error, Fail};
use reqwest::StatusCode; use reqwest::StatusCode;
use std::io; use std::io;
@ -16,6 +16,9 @@ pub enum AnkiError {
#[fail(display = "invalid card template: {}", info)] #[fail(display = "invalid card template: {}", info)]
TemplateError { info: String }, TemplateError { info: String },
#[fail(display = "unable to save template {}", ordinal)]
TemplateSaveError { ordinal: usize },
#[fail(display = "I/O error: {}", info)] #[fail(display = "I/O error: {}", info)]
IOError { info: String }, IOError { info: String },
@ -107,6 +110,10 @@ impl AnkiError {
// already localized // already localized
info.into() info.into()
} }
AnkiError::TemplateSaveError { ordinal } => i18n.trn(
TR::CardTemplatesInvalidTemplateNumber,
tr_args!["number"=>ordinal+1],
),
AnkiError::DBError { info, kind } => match kind { AnkiError::DBError { info, kind } => match kind {
DBErrorKind::Corrupt => info.clone(), DBErrorKind::Corrupt => info.clone(),
DBErrorKind::Locked => "Anki already open, or media currently syncing.".into(), DBErrorKind::Locked => "Anki already open, or media currently syncing.".into(),

View File

@ -229,9 +229,7 @@ impl NoteType {
} }
}); });
if let Some(idx) = invalid_card_idx { if let Some(idx) = invalid_card_idx {
return Err(AnkiError::TemplateError { return Err(AnkiError::TemplateSaveError { ordinal: idx });
info: format!("invalid card {}", idx + 1),
});
} }
let reqs = self.updated_requirements(&parsed_templates); let reqs = self.updated_requirements(&parsed_templates);

View File

@ -5,15 +5,16 @@ use crate::{
err::{AnkiError, Result}, err::{AnkiError, Result},
notetype::NoteTypeID, notetype::NoteTypeID,
}; };
use lazy_static::lazy_static;
use nom::{ use nom::{
branch::alt, branch::alt,
bytes::complete::{escaped, is_not, tag, take_while1}, bytes::complete::{escaped, is_not, tag, take_while1},
character::complete::{anychar, char, one_of}, character::complete::{anychar, char, one_of},
character::is_digit,
combinator::{all_consuming, map, map_res}, combinator::{all_consuming, map, map_res},
sequence::{delimited, preceded, tuple}, sequence::{delimited, preceded, tuple},
{multi::many0, IResult}, {multi::many0, IResult},
}; };
use regex::Regex;
use std::{borrow::Cow, num}; use std::{borrow::Cow, num};
// fixme: need to preserve \ when used twice in string // fixme: need to preserve \ when used twice in string
@ -294,10 +295,13 @@ fn search_node_for_text_with_argument<'a>(
/// ensure a list of ids contains only numbers and commas, returning unchanged if true /// ensure a list of ids contains only numbers and commas, returning unchanged if true
/// used by nid: and cid: /// used by nid: and cid:
fn check_id_list(s: Cow<str>) -> ParseResult<Cow<str>> { fn check_id_list(s: Cow<str>) -> ParseResult<Cow<str>> {
if s.is_empty() || s.as_bytes().iter().any(|&c| !is_digit(c) && c != b',') { lazy_static! {
Err(ParseError {}) static ref RE: Regex = Regex::new(r"^(\d+,)*\d+$").unwrap();
} else { }
if RE.is_match(s.as_ref()) {
Ok(s) Ok(s)
} else {
Err(ParseError {})
} }
} }

View File

@ -34,7 +34,7 @@
"sass-loader": "^8.0.2", "sass-loader": "^8.0.2",
"style-loader": "^1.2.1", "style-loader": "^1.2.1",
"svelte": "^3.23.2", "svelte": "^3.23.2",
"svelte-check": "^0.1.58", "svelte-check": "^0.1.59",
"svelte-loader": "^2.13.6", "svelte-loader": "^2.13.6",
"svelte-preprocess": "^3.9.9", "svelte-preprocess": "^3.9.9",
"ts-loader": "^7.0.5", "ts-loader": "^7.0.5",

View File

@ -36,7 +36,7 @@
<svg <svg
bind:this={svg} bind:this={svg}
viewBox={`0 0 ${bounds.width} ${bounds.height}`} viewBox={`0 0 ${bounds.width} ${bounds.height}`}
style="opacity: {graphData.totalCards ? 1 : 0};"> style="opacity: {graphData.totalCards ? 1 : 0}">
<g class="days" /> <g class="days" />
</svg> </svg>