mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 15:32:23 -04:00
split out tags, deck config and card rendering
This commit is contained in:
parent
1b8d6c6e85
commit
cd14987812
6 changed files with 283 additions and 243 deletions
|
@ -160,7 +160,9 @@ def render_service(
|
||||||
|
|
||||||
for service in pb.ServiceIndex.DESCRIPTOR.values:
|
for service in pb.ServiceIndex.DESCRIPTOR.values:
|
||||||
# SERVICE_INDEX_TEST -> _TESTSERVICE
|
# SERVICE_INDEX_TEST -> _TESTSERVICE
|
||||||
service_var = service.name.replace("SERVICE_INDEX", "") + "SERVICE"
|
service_var = (
|
||||||
|
"_" + service.name.replace("SERVICE_INDEX", "").replace("_", "") + "SERVICE"
|
||||||
|
)
|
||||||
service_obj = getattr(pb, service_var)
|
service_obj = getattr(pb, service_var)
|
||||||
service_index = service.number
|
service_index = service.number
|
||||||
render_service(service_obj, service_index)
|
render_service(service_obj, service_index)
|
||||||
|
|
|
@ -83,8 +83,11 @@ enum ServiceIndex {
|
||||||
SERVICE_INDEX_DECKS = 1;
|
SERVICE_INDEX_DECKS = 1;
|
||||||
SERVICE_INDEX_NOTES = 2;
|
SERVICE_INDEX_NOTES = 2;
|
||||||
SERVICE_INDEX_SYNC = 3;
|
SERVICE_INDEX_SYNC = 3;
|
||||||
SERVICE_INDEX_NOTETYPES = 4;
|
SERVICE_INDEX_NOTE_TYPES = 4;
|
||||||
SERVICE_INDEX_CONFIG = 5;
|
SERVICE_INDEX_CONFIG = 5;
|
||||||
|
SERVICE_INDEX_CARD_RENDERING = 6;
|
||||||
|
SERVICE_INDEX_DECK_CONFIG = 7;
|
||||||
|
SERVICE_INDEX_TAGS = 8;
|
||||||
SERVICE_INDEX_BACKEND = 99;
|
SERVICE_INDEX_BACKEND = 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,18 +182,36 @@ service NoteTypesService {
|
||||||
rpc RemoveNotetype(NoteTypeID) returns (Empty);
|
rpc RemoveNotetype(NoteTypeID) returns (Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
service BackendService {
|
service CardRenderingService {
|
||||||
rpc LatestProgress(Empty) returns (Progress);
|
|
||||||
rpc SetWantsAbort(Empty) returns (Empty);
|
|
||||||
|
|
||||||
// card rendering
|
|
||||||
|
|
||||||
rpc ExtractAVTags(ExtractAVTagsIn) returns (ExtractAVTagsOut);
|
rpc ExtractAVTags(ExtractAVTagsIn) returns (ExtractAVTagsOut);
|
||||||
rpc ExtractLatex(ExtractLatexIn) returns (ExtractLatexOut);
|
rpc ExtractLatex(ExtractLatexIn) returns (ExtractLatexOut);
|
||||||
rpc GetEmptyCards(Empty) returns (EmptyCardsReport);
|
rpc GetEmptyCards(Empty) returns (EmptyCardsReport);
|
||||||
rpc RenderExistingCard(RenderExistingCardIn) returns (RenderCardOut);
|
rpc RenderExistingCard(RenderExistingCardIn) returns (RenderCardOut);
|
||||||
rpc RenderUncommittedCard(RenderUncommittedCardIn) returns (RenderCardOut);
|
rpc RenderUncommittedCard(RenderUncommittedCardIn) returns (RenderCardOut);
|
||||||
rpc StripAVTags(String) returns (String);
|
rpc StripAVTags(String) returns (String);
|
||||||
|
}
|
||||||
|
|
||||||
|
service DeckConfigService {
|
||||||
|
rpc AddOrUpdateDeckConfigLegacy(AddOrUpdateDeckConfigLegacyIn)
|
||||||
|
returns (DeckConfigID);
|
||||||
|
rpc AllDeckConfigLegacy(Empty) returns (Json);
|
||||||
|
rpc GetDeckConfigLegacy(DeckConfigID) returns (Json);
|
||||||
|
rpc NewDeckConfigLegacy(Empty) returns (Json);
|
||||||
|
rpc RemoveDeckConfig(DeckConfigID) returns (Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
service TagsService {
|
||||||
|
rpc ClearUnusedTags(Empty) returns (Empty);
|
||||||
|
rpc AllTags(Empty) returns (StringList);
|
||||||
|
rpc SetTagExpanded(SetTagExpandedIn) returns (Empty);
|
||||||
|
rpc ClearTag(String) returns (Empty);
|
||||||
|
rpc TagTree(Empty) returns (TagTreeNode);
|
||||||
|
rpc DragDropTags(DragDropTagsIn) returns (Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
service BackendService {
|
||||||
|
rpc LatestProgress(Empty) returns (Progress);
|
||||||
|
rpc SetWantsAbort(Empty) returns (Empty);
|
||||||
|
|
||||||
// searching
|
// searching
|
||||||
|
|
||||||
|
@ -216,15 +237,6 @@ service BackendService {
|
||||||
rpc EmptyTrash(Empty) returns (Empty);
|
rpc EmptyTrash(Empty) returns (Empty);
|
||||||
rpc RestoreTrash(Empty) returns (Empty);
|
rpc RestoreTrash(Empty) returns (Empty);
|
||||||
|
|
||||||
// deck config
|
|
||||||
|
|
||||||
rpc AddOrUpdateDeckConfigLegacy(AddOrUpdateDeckConfigLegacyIn)
|
|
||||||
returns (DeckConfigID);
|
|
||||||
rpc AllDeckConfigLegacy(Empty) returns (Json);
|
|
||||||
rpc GetDeckConfigLegacy(DeckConfigID) returns (Json);
|
|
||||||
rpc NewDeckConfigLegacy(Empty) returns (Json);
|
|
||||||
rpc RemoveDeckConfig(DeckConfigID) returns (Empty);
|
|
||||||
|
|
||||||
// cards
|
// cards
|
||||||
|
|
||||||
rpc GetCard(CardID) returns (Card);
|
rpc GetCard(CardID) returns (Card);
|
||||||
|
@ -247,15 +259,6 @@ service BackendService {
|
||||||
rpc FormatTimespan(FormatTimespanIn) returns (String);
|
rpc FormatTimespan(FormatTimespanIn) returns (String);
|
||||||
rpc I18nResources(Empty) returns (Json);
|
rpc I18nResources(Empty) returns (Json);
|
||||||
rpc RenderMarkdown(RenderMarkdownIn) returns (String);
|
rpc RenderMarkdown(RenderMarkdownIn) returns (String);
|
||||||
|
|
||||||
// tags
|
|
||||||
|
|
||||||
rpc ClearUnusedTags(Empty) returns (Empty);
|
|
||||||
rpc AllTags(Empty) returns (StringList);
|
|
||||||
rpc SetTagExpanded(SetTagExpandedIn) returns (Empty);
|
|
||||||
rpc ClearTag(String) returns (Empty);
|
|
||||||
rpc TagTree(Empty) returns (TagTreeNode);
|
|
||||||
rpc DragDropTags(DragDropTagsIn) returns (Empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protobuf stored in .anki2 files
|
// Protobuf stored in .anki2 files
|
||||||
|
|
119
rslib/src/backend/cardrendering.rs
Normal file
119
rslib/src/backend/cardrendering.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
use super::Backend;
|
||||||
|
use crate::{
|
||||||
|
backend_proto as pb,
|
||||||
|
latex::{extract_latex, extract_latex_expanding_clozes, ExtractedLatex},
|
||||||
|
notetype::CardTemplateSchema11,
|
||||||
|
prelude::*,
|
||||||
|
text::{extract_av_tags, strip_av_tags, AVTag},
|
||||||
|
};
|
||||||
|
pub(super) use pb::cardrendering_service::Service as CardRenderingService;
|
||||||
|
|
||||||
|
impl CardRenderingService for Backend {
|
||||||
|
fn extract_av_tags(&self, input: pb::ExtractAvTagsIn) -> Result<pb::ExtractAvTagsOut> {
|
||||||
|
let (text, tags) = extract_av_tags(&input.text, input.question_side);
|
||||||
|
let pt_tags = tags
|
||||||
|
.into_iter()
|
||||||
|
.map(|avtag| match avtag {
|
||||||
|
AVTag::SoundOrVideo(file) => pb::AvTag {
|
||||||
|
value: Some(pb::av_tag::Value::SoundOrVideo(file)),
|
||||||
|
},
|
||||||
|
AVTag::TextToSpeech {
|
||||||
|
field_text,
|
||||||
|
lang,
|
||||||
|
voices,
|
||||||
|
other_args,
|
||||||
|
speed,
|
||||||
|
} => pb::AvTag {
|
||||||
|
value: Some(pb::av_tag::Value::Tts(pb::TtsTag {
|
||||||
|
field_text,
|
||||||
|
lang,
|
||||||
|
voices,
|
||||||
|
other_args,
|
||||||
|
speed,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(pb::ExtractAvTagsOut {
|
||||||
|
text: text.into(),
|
||||||
|
av_tags: pt_tags,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_latex(&self, input: pb::ExtractLatexIn) -> Result<pb::ExtractLatexOut> {
|
||||||
|
let func = if input.expand_clozes {
|
||||||
|
extract_latex_expanding_clozes
|
||||||
|
} else {
|
||||||
|
extract_latex
|
||||||
|
};
|
||||||
|
let (text, extracted) = func(&input.text, input.svg);
|
||||||
|
|
||||||
|
Ok(pb::ExtractLatexOut {
|
||||||
|
text,
|
||||||
|
latex: extracted
|
||||||
|
.into_iter()
|
||||||
|
.map(|e: ExtractedLatex| pb::ExtractedLatex {
|
||||||
|
filename: e.fname,
|
||||||
|
latex_body: e.latex,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_empty_cards(&self, _input: pb::Empty) -> Result<pb::EmptyCardsReport> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
let mut empty = col.empty_cards()?;
|
||||||
|
let report = col.empty_cards_report(&mut empty)?;
|
||||||
|
|
||||||
|
let mut outnotes = vec![];
|
||||||
|
for (_ntid, notes) in empty {
|
||||||
|
outnotes.extend(notes.into_iter().map(|e| {
|
||||||
|
pb::empty_cards_report::NoteWithEmptyCards {
|
||||||
|
note_id: e.nid.0,
|
||||||
|
will_delete_note: e.empty.len() == e.current_count,
|
||||||
|
card_ids: e.empty.into_iter().map(|(_ord, id)| id.0).collect(),
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Ok(pb::EmptyCardsReport {
|
||||||
|
report,
|
||||||
|
notes: outnotes,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_existing_card(&self, input: pb::RenderExistingCardIn) -> Result<pb::RenderCardOut> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
col.render_existing_card(CardID(input.card_id), input.browser)
|
||||||
|
.map(Into::into)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_uncommitted_card(
|
||||||
|
&self,
|
||||||
|
input: pb::RenderUncommittedCardIn,
|
||||||
|
) -> Result<pb::RenderCardOut> {
|
||||||
|
let schema11: CardTemplateSchema11 = serde_json::from_slice(&input.template)?;
|
||||||
|
let template = schema11.into();
|
||||||
|
let mut note = input
|
||||||
|
.note
|
||||||
|
.ok_or_else(|| AnkiError::invalid_input("missing note"))?
|
||||||
|
.into();
|
||||||
|
let ord = input.card_ord as u16;
|
||||||
|
let fill_empty = input.fill_empty;
|
||||||
|
self.with_col(|col| {
|
||||||
|
col.render_uncommitted_card(&mut note, &template, ord, fill_empty)
|
||||||
|
.map(Into::into)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strip_av_tags(&self, input: pb::String) -> Result<pb::String> {
|
||||||
|
Ok(pb::String {
|
||||||
|
val: strip_av_tags(&input.val).into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
60
rslib/src/backend/deckconfig.rs
Normal file
60
rslib/src/backend/deckconfig.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
use super::Backend;
|
||||||
|
use crate::{
|
||||||
|
backend_proto as pb,
|
||||||
|
deckconf::{DeckConf, DeckConfSchema11},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
pub(super) use pb::deckconfig_service::Service as DeckConfigService;
|
||||||
|
|
||||||
|
impl DeckConfigService for Backend {
|
||||||
|
fn add_or_update_deck_config_legacy(
|
||||||
|
&self,
|
||||||
|
input: pb::AddOrUpdateDeckConfigLegacyIn,
|
||||||
|
) -> Result<pb::DeckConfigId> {
|
||||||
|
let conf: DeckConfSchema11 = serde_json::from_slice(&input.config)?;
|
||||||
|
let mut conf: DeckConf = conf.into();
|
||||||
|
self.with_col(|col| {
|
||||||
|
col.transact(None, |col| {
|
||||||
|
col.add_or_update_deck_config(&mut conf, input.preserve_usn_and_mtime)?;
|
||||||
|
Ok(pb::DeckConfigId { dcid: conf.id.0 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_deck_config_legacy(&self, _input: pb::Empty) -> Result<pb::Json> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
let conf: Vec<DeckConfSchema11> = col
|
||||||
|
.storage
|
||||||
|
.all_deck_config()?
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect();
|
||||||
|
serde_json::to_vec(&conf).map_err(Into::into)
|
||||||
|
})
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_deck_config_legacy(&self, input: pb::DeckConfigId) -> Result<pb::Json> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
let conf = col.get_deck_config(input.into(), true)?.unwrap();
|
||||||
|
let conf: DeckConfSchema11 = conf.into();
|
||||||
|
Ok(serde_json::to_vec(&conf)?)
|
||||||
|
})
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_deck_config_legacy(&self, _input: pb::Empty) -> Result<pb::Json> {
|
||||||
|
serde_json::to_vec(&DeckConfSchema11::default())
|
||||||
|
.map_err(Into::into)
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_deck_config(&self, input: pb::DeckConfigId) -> Result<pb::Empty> {
|
||||||
|
self.with_col(|col| col.transact(None, |col| col.remove_deck_config(input.into())))
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,10 @@
|
||||||
|
|
||||||
mod adding;
|
mod adding;
|
||||||
mod card;
|
mod card;
|
||||||
|
mod cardrendering;
|
||||||
mod config;
|
mod config;
|
||||||
mod dbproxy;
|
mod dbproxy;
|
||||||
|
mod deckconfig;
|
||||||
mod decks;
|
mod decks;
|
||||||
mod err;
|
mod err;
|
||||||
mod generic;
|
mod generic;
|
||||||
|
@ -14,38 +16,40 @@ mod progress;
|
||||||
mod scheduler;
|
mod scheduler;
|
||||||
mod search;
|
mod search;
|
||||||
mod sync;
|
mod sync;
|
||||||
|
mod tags;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
|
cardrendering::CardRenderingService,
|
||||||
config::ConfigService,
|
config::ConfigService,
|
||||||
|
deckconfig::DeckConfigService,
|
||||||
decks::DecksService,
|
decks::DecksService,
|
||||||
notes::NotesService,
|
notes::NotesService,
|
||||||
notetypes::NoteTypesService,
|
notetypes::NoteTypesService,
|
||||||
scheduler::SchedulingService,
|
scheduler::SchedulingService,
|
||||||
sync::{SyncService, SyncState},
|
sync::{SyncService, SyncState},
|
||||||
|
tags::TagsService,
|
||||||
};
|
};
|
||||||
use crate::backend_proto::backend_service::Service as BackendService;
|
use crate::backend_proto::backend_service::Service as BackendService;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::dbproxy::db_command_bytes,
|
backend::dbproxy::db_command_bytes,
|
||||||
backend_proto as pb,
|
backend_proto as pb,
|
||||||
backend_proto::{AddOrUpdateDeckConfigLegacyIn, RenderedTemplateReplacement},
|
backend_proto::RenderedTemplateReplacement,
|
||||||
card::{Card, CardID},
|
card::{Card, CardID},
|
||||||
collection::{open_collection, Collection},
|
collection::{open_collection, Collection},
|
||||||
deckconf::{DeckConf, DeckConfSchema11},
|
|
||||||
err::{AnkiError, Result},
|
err::{AnkiError, Result},
|
||||||
i18n::I18n,
|
i18n::I18n,
|
||||||
latex::{extract_latex, extract_latex_expanding_clozes, ExtractedLatex},
|
|
||||||
log,
|
log,
|
||||||
log::default_logger,
|
log::default_logger,
|
||||||
markdown::render_markdown,
|
markdown::render_markdown,
|
||||||
media::check::MediaChecker,
|
media::check::MediaChecker,
|
||||||
media::MediaManager,
|
media::MediaManager,
|
||||||
notes::NoteID,
|
notes::NoteID,
|
||||||
notetype::{CardTemplateSchema11, RenderCardOutput},
|
notetype::RenderCardOutput,
|
||||||
scheduler::timespan::{answer_button_time, time_span},
|
scheduler::timespan::{answer_button_time, time_span},
|
||||||
search::{concatenate_searches, replace_search_node, write_nodes, Node},
|
search::{concatenate_searches, replace_search_node, write_nodes, Node},
|
||||||
template::RenderedNode,
|
template::RenderedNode,
|
||||||
text::{extract_av_tags, sanitize_html_no_images, strip_av_tags, AVTag},
|
text::sanitize_html_no_images,
|
||||||
undo::UndoableOpKind,
|
undo::UndoableOpKind,
|
||||||
};
|
};
|
||||||
use fluent::FluentValue;
|
use fluent::FluentValue;
|
||||||
|
@ -108,113 +112,6 @@ impl BackendService for Backend {
|
||||||
Ok(().into())
|
Ok(().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// card rendering
|
|
||||||
|
|
||||||
fn extract_av_tags(&self, input: pb::ExtractAvTagsIn) -> Result<pb::ExtractAvTagsOut> {
|
|
||||||
let (text, tags) = extract_av_tags(&input.text, input.question_side);
|
|
||||||
let pt_tags = tags
|
|
||||||
.into_iter()
|
|
||||||
.map(|avtag| match avtag {
|
|
||||||
AVTag::SoundOrVideo(file) => pb::AvTag {
|
|
||||||
value: Some(pb::av_tag::Value::SoundOrVideo(file)),
|
|
||||||
},
|
|
||||||
AVTag::TextToSpeech {
|
|
||||||
field_text,
|
|
||||||
lang,
|
|
||||||
voices,
|
|
||||||
other_args,
|
|
||||||
speed,
|
|
||||||
} => pb::AvTag {
|
|
||||||
value: Some(pb::av_tag::Value::Tts(pb::TtsTag {
|
|
||||||
field_text,
|
|
||||||
lang,
|
|
||||||
voices,
|
|
||||||
other_args,
|
|
||||||
speed,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(pb::ExtractAvTagsOut {
|
|
||||||
text: text.into(),
|
|
||||||
av_tags: pt_tags,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_latex(&self, input: pb::ExtractLatexIn) -> Result<pb::ExtractLatexOut> {
|
|
||||||
let func = if input.expand_clozes {
|
|
||||||
extract_latex_expanding_clozes
|
|
||||||
} else {
|
|
||||||
extract_latex
|
|
||||||
};
|
|
||||||
let (text, extracted) = func(&input.text, input.svg);
|
|
||||||
|
|
||||||
Ok(pb::ExtractLatexOut {
|
|
||||||
text,
|
|
||||||
latex: extracted
|
|
||||||
.into_iter()
|
|
||||||
.map(|e: ExtractedLatex| pb::ExtractedLatex {
|
|
||||||
filename: e.fname,
|
|
||||||
latex_body: e.latex,
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_empty_cards(&self, _input: pb::Empty) -> Result<pb::EmptyCardsReport> {
|
|
||||||
self.with_col(|col| {
|
|
||||||
let mut empty = col.empty_cards()?;
|
|
||||||
let report = col.empty_cards_report(&mut empty)?;
|
|
||||||
|
|
||||||
let mut outnotes = vec![];
|
|
||||||
for (_ntid, notes) in empty {
|
|
||||||
outnotes.extend(notes.into_iter().map(|e| {
|
|
||||||
pb::empty_cards_report::NoteWithEmptyCards {
|
|
||||||
note_id: e.nid.0,
|
|
||||||
will_delete_note: e.empty.len() == e.current_count,
|
|
||||||
card_ids: e.empty.into_iter().map(|(_ord, id)| id.0).collect(),
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
Ok(pb::EmptyCardsReport {
|
|
||||||
report,
|
|
||||||
notes: outnotes,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_existing_card(&self, input: pb::RenderExistingCardIn) -> Result<pb::RenderCardOut> {
|
|
||||||
self.with_col(|col| {
|
|
||||||
col.render_existing_card(CardID(input.card_id), input.browser)
|
|
||||||
.map(Into::into)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_uncommitted_card(
|
|
||||||
&self,
|
|
||||||
input: pb::RenderUncommittedCardIn,
|
|
||||||
) -> Result<pb::RenderCardOut> {
|
|
||||||
let schema11: CardTemplateSchema11 = serde_json::from_slice(&input.template)?;
|
|
||||||
let template = schema11.into();
|
|
||||||
let mut note = input
|
|
||||||
.note
|
|
||||||
.ok_or_else(|| AnkiError::invalid_input("missing note"))?
|
|
||||||
.into();
|
|
||||||
let ord = input.card_ord as u16;
|
|
||||||
let fill_empty = input.fill_empty;
|
|
||||||
self.with_col(|col| {
|
|
||||||
col.render_uncommitted_card(&mut note, &template, ord, fill_empty)
|
|
||||||
.map(Into::into)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn strip_av_tags(&self, input: pb::String) -> Result<pb::String> {
|
|
||||||
Ok(pb::String {
|
|
||||||
val: strip_av_tags(&input.val).into(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// searching
|
// searching
|
||||||
//-----------------------------------------------
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
@ -384,57 +281,6 @@ impl BackendService for Backend {
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
// deck config
|
|
||||||
//----------------------------------------------------
|
|
||||||
|
|
||||||
fn add_or_update_deck_config_legacy(
|
|
||||||
&self,
|
|
||||||
input: AddOrUpdateDeckConfigLegacyIn,
|
|
||||||
) -> Result<pb::DeckConfigId> {
|
|
||||||
let conf: DeckConfSchema11 = serde_json::from_slice(&input.config)?;
|
|
||||||
let mut conf: DeckConf = conf.into();
|
|
||||||
self.with_col(|col| {
|
|
||||||
col.transact(None, |col| {
|
|
||||||
col.add_or_update_deck_config(&mut conf, input.preserve_usn_and_mtime)?;
|
|
||||||
Ok(pb::DeckConfigId { dcid: conf.id.0 })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.map(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn all_deck_config_legacy(&self, _input: pb::Empty) -> Result<pb::Json> {
|
|
||||||
self.with_col(|col| {
|
|
||||||
let conf: Vec<DeckConfSchema11> = col
|
|
||||||
.storage
|
|
||||||
.all_deck_config()?
|
|
||||||
.into_iter()
|
|
||||||
.map(Into::into)
|
|
||||||
.collect();
|
|
||||||
serde_json::to_vec(&conf).map_err(Into::into)
|
|
||||||
})
|
|
||||||
.map(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_deck_config_legacy(&self, input: pb::DeckConfigId) -> Result<pb::Json> {
|
|
||||||
self.with_col(|col| {
|
|
||||||
let conf = col.get_deck_config(input.into(), true)?.unwrap();
|
|
||||||
let conf: DeckConfSchema11 = conf.into();
|
|
||||||
Ok(serde_json::to_vec(&conf)?)
|
|
||||||
})
|
|
||||||
.map(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_deck_config_legacy(&self, _input: pb::Empty) -> Result<pb::Json> {
|
|
||||||
serde_json::to_vec(&DeckConfSchema11::default())
|
|
||||||
.map_err(Into::into)
|
|
||||||
.map(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_deck_config(&self, input: pb::DeckConfigId) -> Result<pb::Empty> {
|
|
||||||
self.with_col(|col| col.transact(None, |col| col.remove_deck_config(input.into())))
|
|
||||||
.map(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
// cards
|
// cards
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -605,59 +451,6 @@ impl BackendService for Backend {
|
||||||
}
|
}
|
||||||
Ok(text.into())
|
Ok(text.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// tags
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
fn clear_unused_tags(&self, _input: pb::Empty) -> Result<pb::Empty> {
|
|
||||||
self.with_col(|col| col.transact(None, |col| col.clear_unused_tags().map(Into::into)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn all_tags(&self, _input: pb::Empty) -> Result<pb::StringList> {
|
|
||||||
Ok(pb::StringList {
|
|
||||||
vals: self.with_col(|col| {
|
|
||||||
Ok(col
|
|
||||||
.storage
|
|
||||||
.all_tags()?
|
|
||||||
.into_iter()
|
|
||||||
.map(|t| t.name)
|
|
||||||
.collect())
|
|
||||||
})?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_tag_expanded(&self, input: pb::SetTagExpandedIn) -> Result<pb::Empty> {
|
|
||||||
self.with_col(|col| {
|
|
||||||
col.transact(None, |col| {
|
|
||||||
col.set_tag_expanded(&input.name, input.expanded)?;
|
|
||||||
Ok(().into())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_tag(&self, tag: pb::String) -> Result<pb::Empty> {
|
|
||||||
self.with_col(|col| {
|
|
||||||
col.transact(None, |col| {
|
|
||||||
col.storage.clear_tag_and_children(tag.val.as_str())?;
|
|
||||||
Ok(().into())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tag_tree(&self, _input: pb::Empty) -> Result<pb::TagTreeNode> {
|
|
||||||
self.with_col(|col| col.tag_tree())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn drag_drop_tags(&self, input: pb::DragDropTagsIn) -> Result<pb::Empty> {
|
|
||||||
let source_tags = input.source_tags;
|
|
||||||
let target_tag = if input.target_tag.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(input.target_tag)
|
|
||||||
};
|
|
||||||
self.with_col(|col| col.drag_drop_tags(&source_tags, target_tag))
|
|
||||||
.map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
@ -693,9 +486,14 @@ impl Backend {
|
||||||
pb::ServiceIndex::Backend => BackendService::run_method(self, method, input),
|
pb::ServiceIndex::Backend => BackendService::run_method(self, method, input),
|
||||||
pb::ServiceIndex::Decks => DecksService::run_method(self, method, input),
|
pb::ServiceIndex::Decks => DecksService::run_method(self, method, input),
|
||||||
pb::ServiceIndex::Notes => NotesService::run_method(self, method, input),
|
pb::ServiceIndex::Notes => NotesService::run_method(self, method, input),
|
||||||
pb::ServiceIndex::Notetypes => NoteTypesService::run_method(self, method, input),
|
pb::ServiceIndex::NoteTypes => NoteTypesService::run_method(self, method, input),
|
||||||
pb::ServiceIndex::Config => ConfigService::run_method(self, method, input),
|
pb::ServiceIndex::Config => ConfigService::run_method(self, method, input),
|
||||||
pb::ServiceIndex::Sync => SyncService::run_method(self, method, input),
|
pb::ServiceIndex::Sync => SyncService::run_method(self, method, input),
|
||||||
|
pb::ServiceIndex::Tags => TagsService::run_method(self, method, input),
|
||||||
|
pb::ServiceIndex::DeckConfig => DeckConfigService::run_method(self, method, input),
|
||||||
|
pb::ServiceIndex::CardRendering => {
|
||||||
|
CardRenderingService::run_method(self, method, input)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
let backend_err = anki_error_to_proto_error(err, &self.i18n);
|
let backend_err = anki_error_to_proto_error(err, &self.i18n);
|
||||||
|
|
58
rslib/src/backend/tags.rs
Normal file
58
rslib/src/backend/tags.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
use super::Backend;
|
||||||
|
use crate::{backend_proto as pb, prelude::*};
|
||||||
|
pub(super) use pb::tags_service::Service as TagsService;
|
||||||
|
|
||||||
|
impl TagsService for Backend {
|
||||||
|
fn clear_unused_tags(&self, _input: pb::Empty) -> Result<pb::Empty> {
|
||||||
|
self.with_col(|col| col.transact(None, |col| col.clear_unused_tags().map(Into::into)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_tags(&self, _input: pb::Empty) -> Result<pb::StringList> {
|
||||||
|
Ok(pb::StringList {
|
||||||
|
vals: self.with_col(|col| {
|
||||||
|
Ok(col
|
||||||
|
.storage
|
||||||
|
.all_tags()?
|
||||||
|
.into_iter()
|
||||||
|
.map(|t| t.name)
|
||||||
|
.collect())
|
||||||
|
})?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tag_expanded(&self, input: pb::SetTagExpandedIn) -> Result<pb::Empty> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
col.transact(None, |col| {
|
||||||
|
col.set_tag_expanded(&input.name, input.expanded)?;
|
||||||
|
Ok(().into())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_tag(&self, tag: pb::String) -> Result<pb::Empty> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
col.transact(None, |col| {
|
||||||
|
col.storage.clear_tag_and_children(tag.val.as_str())?;
|
||||||
|
Ok(().into())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag_tree(&self, _input: pb::Empty) -> Result<pb::TagTreeNode> {
|
||||||
|
self.with_col(|col| col.tag_tree())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drag_drop_tags(&self, input: pb::DragDropTagsIn) -> Result<pb::Empty> {
|
||||||
|
let source_tags = input.source_tags;
|
||||||
|
let target_tag = if input.target_tag.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(input.target_tag)
|
||||||
|
};
|
||||||
|
self.with_col(|col| col.drag_drop_tags(&source_tags, target_tag))
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue