mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
parent
03814fa1c4
commit
19bbcb4cc0
5 changed files with 51 additions and 17 deletions
|
@ -27,6 +27,8 @@ service CardRenderingService {
|
|||
rpc DecodeIriPaths(generic.String) returns (generic.String);
|
||||
rpc StripHtml(StripHtmlRequest) returns (generic.String);
|
||||
rpc CompareAnswer(CompareAnswerRequest) returns (generic.String);
|
||||
rpc ExtractClozeForTyping(ExtractClozeForTypingRequest)
|
||||
returns (generic.String);
|
||||
}
|
||||
|
||||
message ExtractAVTagsRequest {
|
||||
|
@ -138,3 +140,8 @@ message CompareAnswerRequest {
|
|||
string expected = 1;
|
||||
string provided = 2;
|
||||
}
|
||||
|
||||
message ExtractClozeForTypingRequest {
|
||||
string text = 1;
|
||||
uint32 ordinal = 2;
|
||||
}
|
||||
|
|
|
@ -1219,6 +1219,9 @@ class Collection(DeprecatedNamesMixin):
|
|||
def compare_answer(self, expected: str, provided: str) -> str:
|
||||
return self._backend.compare_answer(expected=expected, provided=provided)
|
||||
|
||||
def extract_cloze_for_typing(self, text: str, ordinal: int) -> str:
|
||||
return self._backend.extract_cloze_for_typing(text=text, ordinal=ordinal)
|
||||
|
||||
# Timeboxing
|
||||
##########################################################################
|
||||
# fixme: there doesn't seem to be a good reason why this code is in main.py
|
||||
|
|
|
@ -630,23 +630,8 @@ class Reviewer:
|
|||
|
||||
return re.sub(self.typeAnsPat, repl, buf)
|
||||
|
||||
def _contentForCloze(self, txt: str, idx: int) -> str:
|
||||
matches = re.findall(r"\{\{c%s::(.+?)\}\}" % idx, txt, re.DOTALL)
|
||||
if not matches:
|
||||
return None
|
||||
|
||||
def noHint(txt: str) -> str:
|
||||
if "::" in txt:
|
||||
return txt.split("::")[0]
|
||||
return txt
|
||||
|
||||
matches = [noHint(txt) for txt in matches]
|
||||
uniqMatches = set(matches)
|
||||
if len(uniqMatches) == 1:
|
||||
txt = matches[0]
|
||||
else:
|
||||
txt = ", ".join(matches)
|
||||
return txt
|
||||
def _contentForCloze(self, txt: str, idx: int) -> str | None:
|
||||
return self.mw.col.extract_cloze_for_typing(txt, idx) or None
|
||||
|
||||
def _getTypedAnswer(self) -> None:
|
||||
self.web.evalWithCallback("getTypedAnswer();", self._onTypedAnswer)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
use super::Backend;
|
||||
use crate::card_rendering::extract_av_tags;
|
||||
use crate::card_rendering::strip_av_tags;
|
||||
use crate::cloze::extract_cloze_for_typing;
|
||||
use crate::latex::extract_latex;
|
||||
use crate::latex::extract_latex_expanding_clozes;
|
||||
use crate::latex::ExtractedLatex;
|
||||
|
@ -12,6 +13,7 @@ use crate::notetype::CardTemplateSchema11;
|
|||
use crate::notetype::RenderCardOutput;
|
||||
use crate::pb;
|
||||
pub(super) use crate::pb::card_rendering::cardrendering_service::Service as CardRenderingService;
|
||||
use crate::pb::card_rendering::ExtractClozeForTypingRequest;
|
||||
use crate::prelude::*;
|
||||
use crate::template::RenderedNode;
|
||||
use crate::text::decode_iri_paths;
|
||||
|
@ -164,6 +166,15 @@ impl CardRenderingService for Backend {
|
|||
) -> Result<pb::generic::String> {
|
||||
Ok(compare_answer(&input.expected, &input.provided).into())
|
||||
}
|
||||
|
||||
fn extract_cloze_for_typing(
|
||||
&self,
|
||||
input: ExtractClozeForTypingRequest,
|
||||
) -> Result<pb::generic::String> {
|
||||
Ok(extract_cloze_for_typing(&input.text, input.ordinal as u16)
|
||||
.to_string()
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn rendered_nodes_to_proto(
|
||||
|
|
|
@ -306,6 +306,21 @@ pub fn reveal_cloze_text_only(text: &str, cloze_ord: u16, question: bool) -> Cow
|
|||
output.join(", ").into()
|
||||
}
|
||||
|
||||
pub fn extract_cloze_for_typing(text: &str, cloze_ord: u16) -> Cow<str> {
|
||||
let mut output = Vec::new();
|
||||
for node in &parse_text_with_clozes(text) {
|
||||
reveal_cloze_text_in_nodes(node, cloze_ord, false, &mut output);
|
||||
}
|
||||
if output.is_empty() {
|
||||
"".into()
|
||||
} else if output.iter().min() == output.iter().max() {
|
||||
// If all matches are identical text, they get collapsed into a single entry
|
||||
output.pop().unwrap().into()
|
||||
} else {
|
||||
output.join(", ").into()
|
||||
}
|
||||
}
|
||||
|
||||
/// If text contains any LaTeX tags, render the front and back
|
||||
/// of each cloze deletion so that LaTeX can be generated. If
|
||||
/// no LaTeX is found, returns an empty string.
|
||||
|
@ -419,6 +434,19 @@ mod test {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clozes_for_typing() {
|
||||
assert_eq!(extract_cloze_for_typing("{{c2::foo}}", 1), "");
|
||||
assert_eq!(
|
||||
extract_cloze_for_typing("{{c1::foo}} {{c1::bar}} {{c1::foo}}", 1),
|
||||
"foo, bar, foo"
|
||||
);
|
||||
assert_eq!(
|
||||
extract_cloze_for_typing("{{c1::foo}} {{c1::foo}} {{c1::foo}}", 1),
|
||||
"foo"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_cloze_plain_text() {
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in a new issue