Merge branch 'master' into resethook

This commit is contained in:
Henrik Giesel 2020-08-17 12:39:09 +02:00 committed by GitHub
commit dcf82fb403
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 64 additions and 51 deletions

View file

@ -1565,7 +1565,7 @@ where id in %s"""
newRow = max(newRow, 0) newRow = max(newRow, 0)
self.model.focusedCard = self.model.cards[newRow] self.model.focusedCard = self.model.cards[newRow]
self.model.endReset() self.model.endReset()
self.mw.requireReset(reason=ResetReason.BrowserDeleteNote, context=self) self.mw.reset()
tooltip( tooltip(
ngettext("%d note deleted.", "%d notes deleted.", len(nids)) % len(nids) ngettext("%d note deleted.", "%d notes deleted.", len(nids)) % len(nids)
) )

View file

@ -491,7 +491,7 @@ class Editor:
self.web.eval("setBackgrounds(%s);" % json.dumps(cols)) self.web.eval("setBackgrounds(%s);" % json.dumps(cols))
def showDupes(self): def showDupes(self):
contents = stripHTMLMedia(self.note.fields[0]) contents = html.escape(stripHTMLMedia(self.note.fields[0]))
browser = aqt.dialogs.open("Browser", self.mw) browser = aqt.dialogs.open("Browser", self.mw)
browser.form.searchEdit.lineEdit().setText( browser.form.searchEdit.lineEdit().setText(
'"dupe:%s,%s"' % (self.note.model()["id"], contents) '"dupe:%s,%s"' % (self.note.model()["id"], contents)

View file

@ -907,6 +907,7 @@ title="%s" %s>%s</button>""" % (
self.media_syncer.start() self.media_syncer.start()
def on_collection_sync_finished(): def on_collection_sync_finished():
self.col.clearUndo()
self.reset() self.reset()
after_sync() after_sync()

View file

@ -19,7 +19,7 @@ pub(super) fn open_or_create<P: AsRef<Path>>(path: P) -> Result<Connection> {
db.pragma_update(None, "page_size", &4096)?; db.pragma_update(None, "page_size", &4096)?;
db.pragma_update(None, "legacy_file_format", &false)?; db.pragma_update(None, "legacy_file_format", &false)?;
db.pragma_update(None, "journal", &"wal")?; db.pragma_update_and_check(None, "journal_mode", &"wal", |_| Ok(()))?;
initial_db_setup(&mut db)?; initial_db_setup(&mut db)?;

View file

@ -274,6 +274,8 @@ impl Collection {
// nothing to do // nothing to do
return Ok(()); return Ok(());
} }
} else {
return Err(AnkiError::NotFound);
} }
self.transact(None, |col| { self.transact(None, |col| {

View file

@ -163,15 +163,26 @@ impl NoteType {
.collect() .collect()
} }
/// Adjust sort index to match repositioned fields.
fn reposition_sort_idx(&mut self) { fn reposition_sort_idx(&mut self) {
let adjusted_idx = self.fields.iter().enumerate().find_map(|(idx, f)| { self.config.sort_field_idx = self
.fields
.iter()
.enumerate()
.find_map(|(idx, f)| {
if f.ord == Some(self.config.sort_field_idx) { if f.ord == Some(self.config.sort_field_idx) {
Some(idx) Some(idx as u32)
} else { } else {
None None
} }
})
.unwrap_or_else(|| {
// provided ordinal not on any existing field; cap to bounds
self.config
.sort_field_idx
.max(0)
.min((self.fields.len() - 1) as u32)
}); });
self.config.sort_field_idx = adjusted_idx.unwrap_or(0) as u32;
} }
pub(crate) fn normalize_names(&mut self) { pub(crate) fn normalize_names(&mut self) {

View file

@ -9,11 +9,9 @@ use crate::{
err::Result, err::Result,
notes::field_checksum, notes::field_checksum,
notetype::NoteTypeID, notetype::NoteTypeID,
text::matches_wildcard, text::{matches_wildcard, text_to_re},
text::{normalize_to_nfc, strip_html_preserving_image_filenames, without_combining}, text::{normalize_to_nfc, strip_html_preserving_image_filenames, without_combining},
}; };
use lazy_static::lazy_static;
use regex::{Captures, Regex};
use std::{borrow::Cow, fmt::Write}; use std::{borrow::Cow, fmt::Write};
pub(crate) struct SqlWriter<'a> { pub(crate) struct SqlWriter<'a> {
@ -458,38 +456,6 @@ fn glob_to_re(glob: &str) -> Option<String> {
Some(text_to_re(glob)) Some(text_to_re(glob))
} }
/// Escape text, converting glob characters to regex syntax, then return.
fn text_to_re(glob: &str) -> String {
lazy_static! {
static ref ESCAPED: Regex = Regex::new(r"(\\\\)?\\\*").unwrap();
static ref GLOB: Regex = Regex::new(r"(\\\\)?[_%]").unwrap();
}
let escaped = regex::escape(glob);
let text = ESCAPED.replace_all(&escaped, |caps: &Captures| {
if caps.get(0).unwrap().as_str().len() == 2 {
".*"
} else {
r"\*"
}
});
let text2 = GLOB.replace_all(&text, |caps: &Captures| {
match caps.get(0).unwrap().as_str() {
"_" => ".",
"%" => ".*",
other => {
// strip off the escaping char
&other[2..]
}
}
.to_string()
});
text2.into()
}
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
pub enum RequiredTable { pub enum RequiredTable {
Notes, Notes,

View file

@ -5,6 +5,7 @@ use crate::{
collection::Collection, collection::Collection,
err::{AnkiError, Result}, err::{AnkiError, Result},
notes::{NoteID, TransformNoteOutput}, notes::{NoteID, TransformNoteOutput},
text::text_to_re,
{text::normalize_to_nfc, types::Usn}, {text::normalize_to_nfc, types::Usn},
}; };
use regex::{NoExpand, Regex, Replacer}; use regex::{NoExpand, Regex, Replacer};
@ -123,11 +124,7 @@ impl Collection {
// generate regexps // generate regexps
let tags = split_tags(tags) let tags = split_tags(tags)
.map(|tag| { .map(|tag| {
let tag = if regex { let tag = if regex { tag.into() } else { text_to_re(tag) };
tag.into()
} else {
regex::escape(tag)
};
Regex::new(&format!("(?i){}", tag)) Regex::new(&format!("(?i){}", tag))
.map_err(|_| AnkiError::invalid_input("invalid regex")) .map_err(|_| AnkiError::invalid_input("invalid regex"))
}) })
@ -234,6 +231,10 @@ mod test {
let note = col.storage.get_note(note.id)?.unwrap(); let note = col.storage.get_note(note.id)?.unwrap();
assert_eq!(note.tags[0], "bar"); assert_eq!(note.tags[0], "bar");
col.replace_tags_for_notes(&[note.id], "b*r", "baz", false)?;
let note = col.storage.get_note(note.id)?.unwrap();
assert_eq!(note.tags[0], "baz");
col.replace_tags_for_notes(&[note.id], "b.r", "baz", true)?; col.replace_tags_for_notes(&[note.id], "b.r", "baz", true)?;
let note = col.storage.get_note(note.id)?.unwrap(); let note = col.storage.get_note(note.id)?.unwrap();
assert_eq!(note.tags[0], "baz"); assert_eq!(note.tags[0], "baz");

View file

@ -261,6 +261,38 @@ pub(crate) fn without_combining(s: &str) -> Cow<str> {
.into() .into()
} }
/// Escape text, converting glob characters to regex syntax, then return.
pub(crate) fn text_to_re(glob: &str) -> String {
lazy_static! {
static ref ESCAPED: Regex = Regex::new(r"(\\\\)?\\\*").unwrap();
static ref GLOB: Regex = Regex::new(r"(\\\\)?[_%]").unwrap();
}
let escaped = regex::escape(glob);
let text = ESCAPED.replace_all(&escaped, |caps: &Captures| {
if caps.get(0).unwrap().as_str().len() == 2 {
".*"
} else {
r"\*"
}
});
let text2 = GLOB.replace_all(&text, |caps: &Captures| {
match caps.get(0).unwrap().as_str() {
"_" => ".",
"%" => ".*",
other => {
// strip off the escaping char
&other[2..]
}
}
.to_string()
});
text2.into()
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::matches_wildcard; use super::matches_wildcard;