mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
Implement replace_search_term
This commit is contained in:
parent
79d0b5496b
commit
84061a6e6d
4 changed files with 50 additions and 4 deletions
|
@ -89,6 +89,7 @@ service BackendService {
|
||||||
rpc SearchNotes (SearchNotesIn) returns (SearchNotesOut);
|
rpc SearchNotes (SearchNotesIn) returns (SearchNotesOut);
|
||||||
rpc NegateSearch (String) returns (String);
|
rpc NegateSearch (String) returns (String);
|
||||||
rpc ConcatenateSearches (ConcatenateSearchesIn) returns (String);
|
rpc ConcatenateSearches (ConcatenateSearchesIn) returns (String);
|
||||||
|
rpc ReplaceSearchTerm (ReplaceSearchTermIn) returns (String);
|
||||||
rpc FindAndReplace (FindAndReplaceIn) returns (UInt32);
|
rpc FindAndReplace (FindAndReplaceIn) returns (UInt32);
|
||||||
|
|
||||||
// scheduling
|
// scheduling
|
||||||
|
@ -755,6 +756,20 @@ message BuiltinSearchOrder {
|
||||||
bool reverse = 2;
|
bool reverse = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ConcatenateSearchesIn {
|
||||||
|
enum Separator {
|
||||||
|
AND = 0;
|
||||||
|
OR = 1;
|
||||||
|
}
|
||||||
|
Separator sep = 1;
|
||||||
|
repeated string searches = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ReplaceSearchTermIn {
|
||||||
|
string search = 1;
|
||||||
|
string replacement = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message CloseCollectionIn {
|
message CloseCollectionIn {
|
||||||
bool downgrade_to_schema11 = 1;
|
bool downgrade_to_schema11 = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -435,10 +435,15 @@ impl BackendService for Backend {
|
||||||
fn negate_search(&self, input: pb::String) -> Result<pb::String> {
|
fn negate_search(&self, input: pb::String) -> Result<pb::String> {
|
||||||
Ok(negate_search(&input.val)?.into())
|
Ok(negate_search(&input.val)?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn concatenate_searches(&self, input: pb::ConcatenateSearchesIn) -> Result<pb::String> {
|
fn concatenate_searches(&self, input: pb::ConcatenateSearchesIn) -> Result<pb::String> {
|
||||||
Ok(concatenate_searches(input.sep, &input.searches)?.into())
|
Ok(concatenate_searches(input.sep, &input.searches)?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn replace_search_term(&self, input: pb::ReplaceSearchTermIn) -> Result<pb::String> {
|
||||||
|
Ok(replace_search_term(&input.search, &input.replacement)?.into())
|
||||||
|
}
|
||||||
|
|
||||||
fn find_and_replace(&self, input: pb::FindAndReplaceIn) -> BackendResult<pb::UInt32> {
|
fn find_and_replace(&self, input: pb::FindAndReplaceIn) -> BackendResult<pb::UInt32> {
|
||||||
let mut search = if input.regex {
|
let mut search = if input.regex {
|
||||||
input.search
|
input.search
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub(super) enum Node<'a> {
|
||||||
Search(SearchNode<'a>),
|
Search(SearchNode<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub(super) enum SearchNode<'a> {
|
pub(super) enum SearchNode<'a> {
|
||||||
// text without a colon
|
// text without a colon
|
||||||
UnqualifiedText(Cow<'a, str>),
|
UnqualifiedText(Cow<'a, str>),
|
||||||
|
@ -90,7 +90,7 @@ pub(super) enum SearchNode<'a> {
|
||||||
WordBoundary(Cow<'a, str>),
|
WordBoundary(Cow<'a, str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub(super) enum PropertyKind {
|
pub(super) enum PropertyKind {
|
||||||
Due(i32),
|
Due(i32),
|
||||||
Interval(u32),
|
Interval(u32),
|
||||||
|
@ -99,7 +99,7 @@ pub(super) enum PropertyKind {
|
||||||
Ease(f32),
|
Ease(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub(super) enum StateKind {
|
pub(super) enum StateKind {
|
||||||
New,
|
New,
|
||||||
Review,
|
Review,
|
||||||
|
@ -111,7 +111,7 @@ pub(super) enum StateKind {
|
||||||
Suspended,
|
Suspended,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub(super) enum TemplateKind<'a> {
|
pub(super) enum TemplateKind<'a> {
|
||||||
Ordinal(u16),
|
Ordinal(u16),
|
||||||
Name(Cow<'a, str>),
|
Name(Cow<'a, str>),
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
search::parser::{parse, Node, PropertyKind, SearchNode, StateKind, TemplateKind},
|
search::parser::{parse, Node, PropertyKind, SearchNode, StateKind, TemplateKind},
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
/// Take an Anki-style search string and convert it into an equivalent
|
/// Take an Anki-style search string and convert it into an equivalent
|
||||||
/// search string with normalized syntax.
|
/// search string with normalized syntax.
|
||||||
|
@ -55,6 +56,31 @@ pub fn concatenate_searches(sep: i32, searches: &[String]) -> Result<String> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Take two Anki-style search strings. If the second one evaluates to a single search
|
||||||
|
/// node, replace with it all search terms of the same kind in the first search.
|
||||||
|
/// Then return the possibly modified first search.
|
||||||
|
pub fn replace_search_term(search: &str, replacement: &str) -> Result<String> {
|
||||||
|
let mut nodes = parse(search)?;
|
||||||
|
let new = parse(replacement)?;
|
||||||
|
if let [Node::Search(search_node)] = &new[..] {
|
||||||
|
fn update_node_vec<'a>(old_nodes: &mut [Node<'a>], new_node: &SearchNode<'a>) {
|
||||||
|
fn update_node<'a>(old_node: &mut Node<'a>, new_node: &SearchNode<'a>) {
|
||||||
|
match old_node {
|
||||||
|
Node::Not(n) => update_node(n, new_node),
|
||||||
|
Node::Group(ns) => update_node_vec(ns, new_node),
|
||||||
|
Node::Search(n) => {
|
||||||
|
if mem::discriminant(n) == mem::discriminant(new_node) {
|
||||||
|
*n = new_node.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_nodes.iter_mut().for_each(|n| update_node(n, new_node));
|
||||||
|
}
|
||||||
|
update_node_vec(&mut nodes, search_node);
|
||||||
|
}
|
||||||
|
Ok(write_nodes(&nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_nodes<'a, I>(nodes: I) -> String
|
fn write_nodes<'a, I>(nodes: I) -> String
|
||||||
|
|
Loading…
Reference in a new issue