use native struct for NoteType

This commit is contained in:
Damien Elmes 2020-04-14 08:47:48 +10:00
parent d6646a6db5
commit 8cfb1fad44
9 changed files with 84 additions and 58 deletions

View file

@ -319,7 +319,10 @@ impl Backend {
OValue::SetAllDecks(pb::Empty {}) OValue::SetAllDecks(pb::Empty {})
} }
Value::AllStockNotetypes(_) => OValue::AllStockNotetypes(pb::AllStockNotetypesOut { Value::AllStockNotetypes(_) => OValue::AllStockNotetypes(pb::AllStockNotetypesOut {
notetypes: all_stock_notetypes(&self.i18n), notetypes: all_stock_notetypes(&self.i18n)
.into_iter()
.map(Into::into)
.collect(),
}), }),
}) })
} }

View file

@ -401,12 +401,16 @@ where
&self.mgr.media_folder, &self.mgr.media_folder,
)? { )? {
// note was modified, needs saving // note was modified, needs saving
set_note(&self.ctx.storage.db, note, nt.sort_field_idx())?; set_note(
&self.ctx.storage.db,
note,
nt.config.sort_field_idx as usize,
)?;
collection_modified = true; collection_modified = true;
} }
// extract latex // extract latex
extract_latex_refs(note, &mut referenced_files, nt.latex_uses_svg()); extract_latex_refs(note, &mut referenced_files, nt.config.latex_svg);
Ok(()) Ok(())
})?; })?;

View file

@ -6,7 +6,7 @@ mod stock;
pub use crate::backend_proto::{ pub use crate::backend_proto::{
card_requirement::CardRequirementKind, CardRequirement, CardTemplate, CardTemplateConfig, card_requirement::CardRequirementKind, CardRequirement, CardTemplate, CardTemplateConfig,
NoteField, NoteFieldConfig, NoteType, NoteTypeConfig, NoteTypeKind, NoteField, NoteFieldConfig, NoteType as NoteTypeProto, NoteTypeConfig, NoteTypeKind,
}; };
pub use schema11::{CardTemplateSchema11, NoteFieldSchema11, NoteTypeSchema11}; pub use schema11::{CardTemplateSchema11, NoteFieldSchema11, NoteTypeSchema11};
pub use stock::all_stock_notetypes; pub use stock::all_stock_notetypes;
@ -15,6 +15,8 @@ use crate::{
define_newtype, define_newtype,
template::{without_legacy_template_directives, FieldRequirements, ParsedTemplate}, template::{without_legacy_template_directives, FieldRequirements, ParsedTemplate},
text::ensure_string_in_nfc, text::ensure_string_in_nfc,
timestamp::TimestampSecs,
types::Usn,
}; };
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use unicase::UniCase; use unicase::UniCase;
@ -42,29 +44,35 @@ pub(crate) const DEFAULT_LATEX_HEADER: &str = r#"\documentclass[12pt]{article}
pub(crate) const DEFAULT_LATEX_FOOTER: &str = r#"\end{document}"#; pub(crate) const DEFAULT_LATEX_FOOTER: &str = r#"\end{document}"#;
impl NoteType { pub struct NoteType {
pub fn new() -> Self { pub id: NoteTypeID,
let mut nt = Self::default(); pub name: String,
pub mtime_secs: TimestampSecs,
pub usn: Usn,
pub fields: Vec<NoteField>,
pub templates: Vec<CardTemplate>,
pub config: NoteTypeConfig,
}
impl Default for NoteType {
fn default() -> Self {
let mut conf = NoteTypeConfig::default(); let mut conf = NoteTypeConfig::default();
conf.css = DEFAULT_CSS.into(); conf.css = DEFAULT_CSS.into();
conf.latex_pre = DEFAULT_LATEX_HEADER.into(); conf.latex_pre = DEFAULT_LATEX_HEADER.into();
conf.latex_post = DEFAULT_LATEX_FOOTER.into(); conf.latex_post = DEFAULT_LATEX_FOOTER.into();
nt.config = Some(conf); NoteType {
nt id: NoteTypeID(0),
} name: "".into(),
mtime_secs: TimestampSecs(0),
pub fn id(&self) -> NoteTypeID { usn: Usn(0),
NoteTypeID(self.id) fields: vec![],
} templates: vec![],
config: conf,
pub fn sort_field_idx(&self) -> usize { }
self.config.as_ref().unwrap().sort_field_idx as usize
}
pub fn latex_uses_svg(&self) -> bool {
self.config.as_ref().unwrap().latex_svg
} }
}
impl NoteType {
pub(crate) fn ensure_names_unique(&mut self) { pub(crate) fn ensure_names_unique(&mut self) {
let mut names = HashSet::new(); let mut names = HashSet::new();
for t in &mut self.templates { for t in &mut self.templates {
@ -134,7 +142,7 @@ impl NoteType {
} }
}) })
.collect(); .collect();
self.config.as_mut().unwrap().reqs = reqs; self.config.reqs = reqs;
} }
pub(crate) fn normalize_names(&mut self) { pub(crate) fn normalize_names(&mut self) {
@ -180,3 +188,17 @@ impl NoteType {
self.update_requirements(); self.update_requirements();
} }
} }
impl From<NoteType> for NoteTypeProto {
fn from(nt: NoteType) -> Self {
NoteTypeProto {
id: nt.id.0,
name: nt.name,
mtime_secs: nt.mtime_secs.0 as u32,
usn: nt.usn.0,
config: Some(nt.config),
fields: nt.fields,
templates: nt.templates,
}
}
}

View file

@ -88,11 +88,11 @@ impl NoteTypeSchema11 {
impl From<NoteTypeSchema11> for NoteType { impl From<NoteTypeSchema11> for NoteType {
fn from(nt: NoteTypeSchema11) -> Self { fn from(nt: NoteTypeSchema11) -> Self {
NoteType { NoteType {
id: nt.id.0, id: nt.id,
name: nt.name, name: nt.name,
mtime_secs: nt.mtime.0 as u32, mtime_secs: nt.mtime,
usn: nt.usn.0, usn: nt.usn,
config: Some(NoteTypeConfig { config: NoteTypeConfig {
kind: nt.kind as i32, kind: nt.kind as i32,
sort_field_idx: nt.sortf as u32, sort_field_idx: nt.sortf as u32,
css: nt.css, css: nt.css,
@ -102,7 +102,7 @@ impl From<NoteTypeSchema11> for NoteType {
latex_svg: nt.latexsvg, latex_svg: nt.latexsvg,
reqs: nt.req.0.into_iter().map(Into::into).collect(), reqs: nt.req.0.into_iter().map(Into::into).collect(),
other: other_to_bytes(&nt.other), other: other_to_bytes(&nt.other),
}), },
fields: nt.flds.into_iter().map(Into::into).collect(), fields: nt.flds.into_iter().map(Into::into).collect(),
templates: nt.tmpls.into_iter().map(Into::into).collect(), templates: nt.tmpls.into_iter().map(Into::into).collect(),
} }
@ -134,17 +134,17 @@ fn bytes_to_other(bytes: &[u8]) -> HashMap<String, Value> {
impl From<NoteType> for NoteTypeSchema11 { impl From<NoteType> for NoteTypeSchema11 {
fn from(p: NoteType) -> Self { fn from(p: NoteType) -> Self {
let c = p.config.unwrap(); let c = p.config;
NoteTypeSchema11 { NoteTypeSchema11 {
id: NoteTypeID(p.id), id: p.id,
name: p.name, name: p.name,
kind: if c.kind == 1 { kind: if c.kind == 1 {
NoteTypeKind::Cloze NoteTypeKind::Cloze
} else { } else {
NoteTypeKind::Standard NoteTypeKind::Standard
}, },
mtime: TimestampSecs(p.mtime_secs as i64), mtime: p.mtime_secs,
usn: Usn(p.usn), usn: p.usn,
sortf: c.sort_field_idx as u16, sortf: c.sort_field_idx as u16,
did: if c.target_deck_id == 0 { did: if c.target_deck_id == 0 {
None None

View file

@ -16,7 +16,7 @@ impl SqliteStorage {
if idx == StockNoteType::Basic as usize { if idx == StockNoteType::Basic as usize {
self.set_config_value( self.set_config_value(
ConfigKey::CurrentNoteTypeID.into(), ConfigKey::CurrentNoteTypeID.into(),
&nt.id(), &nt.id,
self.usn(false)?, self.usn(false)?,
TimestampSecs::now(), TimestampSecs::now(),
)?; )?;
@ -43,7 +43,7 @@ fn fieldref<S: AsRef<str>>(name: S) -> String {
} }
pub(crate) fn basic(i18n: &I18n) -> NoteType { pub(crate) fn basic(i18n: &I18n) -> NoteType {
let mut nt = NoteType::new(); let mut nt = NoteType::default();
nt.name = i18n.tr(TR::NotetypesBasicName).into(); nt.name = i18n.tr(TR::NotetypesBasicName).into();
let front = i18n.tr(TR::NotetypesFrontField); let front = i18n.tr(TR::NotetypesFrontField);
let back = i18n.tr(TR::NotetypesBackField); let back = i18n.tr(TR::NotetypesBackField);
@ -108,15 +108,14 @@ pub(crate) fn basic_optional_reverse(i18n: &I18n) -> NoteType {
} }
pub(crate) fn cloze(i18n: &I18n) -> NoteType { pub(crate) fn cloze(i18n: &I18n) -> NoteType {
let mut nt = NoteType::new(); let mut nt = NoteType::default();
nt.name = i18n.tr(TR::NotetypesClozeName).into(); nt.name = i18n.tr(TR::NotetypesClozeName).into();
let text = i18n.tr(TR::NotetypesTextField); let text = i18n.tr(TR::NotetypesTextField);
nt.add_field(text.as_ref()); nt.add_field(text.as_ref());
let fmt = format!("{{{{cloze:{}}}}}", text); let fmt = format!("{{{{cloze:{}}}}}", text);
nt.add_template(nt.name.clone(), fmt.clone(), fmt); nt.add_template(nt.name.clone(), fmt.clone(), fmt);
let mut config = nt.config.as_mut().unwrap(); nt.config.kind = NoteTypeKind::Cloze as i32;
config.kind = NoteTypeKind::Cloze as i32; nt.config.css += "
config.css += "
.cloze { .cloze {
font-weight: bold; font-weight: bold;
color: blue; color: blue;

View file

@ -301,10 +301,10 @@ impl SqlWriter<'_> {
let mut field_map = vec![]; let mut field_map = vec![];
for nt in note_types.values() { for nt in note_types.values() {
let fields = self.col.storage.get_notetype_fields(nt.id())?; let fields = self.col.storage.get_notetype_fields(nt.id)?;
for field in &fields { for field in &fields {
if matches_wildcard(&field.name, field_name) { if matches_wildcard(&field.name, field_name) {
field_map.push((nt.id(), field.ord)); field_map.push((nt.id, field.ord));
} }
} }
} }

View file

@ -3,11 +3,9 @@
use super::SqliteStorage; use super::SqliteStorage;
use crate::{ use crate::{
backend_proto::{ backend_proto::{CardTemplate, CardTemplateConfig, NoteField, NoteFieldConfig, NoteTypeConfig},
CardTemplate, CardTemplateConfig, NoteField, NoteFieldConfig, NoteType, NoteTypeConfig,
},
err::{AnkiError, DBErrorKind, Result}, err::{AnkiError, DBErrorKind, Result},
notetype::{NoteTypeID, NoteTypeSchema11}, notetype::{NoteType, NoteTypeID, NoteTypeSchema11},
timestamp::TimestampMillis, timestamp::TimestampMillis,
}; };
use prost::Message; use prost::Message;
@ -22,7 +20,7 @@ fn row_to_notetype_core(row: &Row) -> Result<NoteType> {
name: row.get(1)?, name: row.get(1)?,
mtime_secs: row.get(2)?, mtime_secs: row.get(2)?,
usn: row.get(3)?, usn: row.get(3)?,
config: Some(config), config,
fields: vec![], fields: vec![],
templates: vec![], templates: vec![],
}) })
@ -41,7 +39,7 @@ impl SqliteStorage {
self.db self.db
.prepare_cached(include_str!("get_notetype.sql"))? .prepare_cached(include_str!("get_notetype.sql"))?
.query_and_then(NO_PARAMS, row_to_notetype_core)? .query_and_then(NO_PARAMS, row_to_notetype_core)?
.map(|ntres| ntres.map(|nt| (nt.id(), nt))) .map(|ntres| ntres.map(|nt| (nt.id, nt)))
.collect() .collect()
} }
@ -86,7 +84,8 @@ impl SqliteStorage {
} }
} }
fn get_all_notetype_meta(&self) -> Result<Vec<(NoteTypeID, String)>> { #[allow(dead_code)]
fn get_all_notetype_names(&self) -> Result<Vec<(NoteTypeID, String)>> {
self.db self.db
.prepare_cached(include_str!("get_notetype_names.sql"))? .prepare_cached(include_str!("get_notetype_names.sql"))?
.query_and_then(NO_PARAMS, |row| Ok((row.get(0)?, row.get(1)?)))? .query_and_then(NO_PARAMS, |row| Ok((row.get(0)?, row.get(1)?)))?
@ -97,7 +96,7 @@ impl SqliteStorage {
&self, &self,
) -> Result<HashMap<NoteTypeID, NoteTypeSchema11>> { ) -> Result<HashMap<NoteTypeID, NoteTypeSchema11>> {
let mut nts = HashMap::new(); let mut nts = HashMap::new();
for (ntid, _name) in self.get_all_notetype_meta()? { for (ntid, _name) in self.get_all_notetype_core()? {
let full = self.get_full_notetype(ntid)?.unwrap(); let full = self.get_full_notetype(ntid)?.unwrap();
nts.insert(ntid, full.into()); nts.insert(ntid, full.into());
} }
@ -149,24 +148,24 @@ impl SqliteStorage {
Ok(()) Ok(())
} }
fn update_notetype_meta(&self, nt: &NoteType) -> Result<()> { fn update_notetype_config(&self, nt: &NoteType) -> Result<()> {
assert!(nt.id != 0); assert!(nt.id.0 != 0);
let mut stmt = self let mut stmt = self
.db .db
.prepare_cached(include_str!("update_notetype_meta.sql"))?; .prepare_cached(include_str!("update_notetype_core.sql"))?;
let mut config_bytes = vec![]; let mut config_bytes = vec![];
nt.config.as_ref().unwrap().encode(&mut config_bytes)?; nt.config.encode(&mut config_bytes)?;
stmt.execute(params![nt.id, nt.name, nt.mtime_secs, nt.usn, config_bytes])?; stmt.execute(params![nt.id, nt.name, nt.mtime_secs, nt.usn, config_bytes])?;
Ok(()) Ok(())
} }
pub(crate) fn add_new_notetype(&self, nt: &mut NoteType) -> Result<()> { pub(crate) fn add_new_notetype(&self, nt: &mut NoteType) -> Result<()> {
assert!(nt.id == 0); assert!(nt.id.0 == 0);
let mut stmt = self.db.prepare_cached(include_str!("add_notetype.sql"))?; let mut stmt = self.db.prepare_cached(include_str!("add_notetype.sql"))?;
let mut config_bytes = vec![]; let mut config_bytes = vec![];
nt.config.as_ref().unwrap().encode(&mut config_bytes)?; nt.config.encode(&mut config_bytes)?;
stmt.execute(params![ stmt.execute(params![
TimestampMillis::now(), TimestampMillis::now(),
nt.name, nt.name,
@ -174,10 +173,10 @@ impl SqliteStorage {
nt.usn, nt.usn,
config_bytes config_bytes
])?; ])?;
nt.id = self.db.last_insert_rowid(); nt.id.0 = self.db.last_insert_rowid();
self.update_notetype_fields(nt.id(), &nt.fields)?; self.update_notetype_fields(nt.id, &nt.fields)?;
self.update_notetype_templates(nt.id(), &nt.templates)?; self.update_notetype_templates(nt.id, &nt.templates)?;
Ok(()) Ok(())
} }
@ -199,7 +198,7 @@ impl SqliteStorage {
} }
nt.name.push('_'); nt.name.push('_');
} }
self.update_notetype_meta(&nt)?; self.update_notetype_config(&nt)?;
self.update_notetype_fields(ntid, &nt.fields)?; self.update_notetype_fields(ntid, &nt.fields)?;
self.update_notetype_templates(ntid, &nt.templates)?; self.update_notetype_templates(ntid, &nt.templates)?;
} }

View file

@ -21,7 +21,6 @@ fn unicase_compare(s1: &str, s2: &str) -> Ordering {
} }
// fixme: rollback savepoint when tags not changed // fixme: rollback savepoint when tags not changed
// fixme: switch away from proto for top level struct
// currently public for dbproxy // currently public for dbproxy
#[derive(Debug)] #[derive(Debug)]