···11# Changelog
2233## Next
44-- Add filtering for specific fields in search, like `artist:apashe`. You can also right-click a column header to add a filter.
44+- Add filtering for specific fields in search, like `artist:apashe` or `album:"mirai sekai"`. You can also right-click a column header to add a filter.
55- Add genre autocomplete
66- Make macOS media key permission request non-intrusive
77- Improve error and crashing behaviour
+46-7
src-native/filter.rs
···174174 filtered_tracks
175175}
176176177177+#[derive(Default, Debug)]
177178struct Keyword {
178179 full_word: String,
179180 field: Option<String>,
180181 literal: String,
181182}
182183impl Keyword {
183183- fn parse(word: &str) -> Keyword {
184184+ fn from_word(word: &str) -> Keyword {
184185 let mut parts = word.splitn(2, ':');
185186 let field = parts.next();
186187 let literal = parts.next();
···197198 },
198199 }
199200 }
201201+ fn parse_next_keyword(query: &mut String) -> Option<Keyword> {
202202+ *query = query.trim_start().to_string();
203203+ if query.is_empty() {
204204+ return None;
205205+ }
206206+207207+ // get next word
208208+ let (word, rest) = match query.find(char::is_whitespace) {
209209+ Some(i) => {
210210+ let (word, rest) = query.split_at(i);
211211+ (word.to_string(), rest.to_string())
212212+ }
213213+ None => (query.to_string(), "".to_string()),
214214+ };
215215+ *query = rest.to_string();
216216+ println!("word: {}", word);
217217+ println!("rest: {}", query);
218218+219219+ let mut keyword = Keyword::from_word(&word);
220220+221221+ // parse field:"literal"
222222+ if keyword.field.is_some() && keyword.literal.starts_with('\"') {
223223+ keyword.literal = keyword.literal.trim_start_matches('\"').to_string();
224224+ let (literal, rest) = match query.split_once('\"') {
225225+ Some((literal, rest)) => (literal.to_string(), rest.to_string()),
226226+ None => (query.to_string(), "".to_string()),
227227+ };
228228+ keyword.literal.push_str(&literal);
229229+ *query = rest;
230230+ println!("word: {}", keyword.literal);
231231+ println!("rest: {}", query);
232232+ }
233233+234234+ Some(keyword)
235235+ }
200236}
201237202238pub fn filter(mut item_ids: Vec<ItemId>, query: String, library: &Library) -> Vec<ItemId> {
···204240 if query == "" {
205241 return item_ids;
206242 }
207207- let query: String = query.nfc().collect();
243243+ let mut query: String = query.nfc().collect();
208244209209- for word in query.split(' ') {
210210- if word == "" {
211211- continue;
212212- }
213213- let keyword = Keyword::parse(word);
245245+ let mut keywords = Vec::new();
246246+ while let Some(keyword) = Keyword::parse_next_keyword(&mut query) {
247247+ keywords.push(keyword);
248248+ }
249249+250250+ println!("Keywords: {keywords:?}");
251251+252252+ for keyword in keywords {
214253 item_ids = filter_keyword(item_ids, keyword, &library);
215254 }
216255 println!("Filter: {}ms", now.elapsed().as_millis());