a fork of iceshrimp.net but a tweaked frontend to my personal liking. waow
fediverse social-media social iceshrimp fedi
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at dev 103 lines 3.2 kB view raw
1namespace Iceshrimp.Parsing; 2 3public static class SearchQueryParser 4{ 5 public static List<ISearchQueryFilter> Parse(ReadOnlySpan<char> input) 6 { 7 var results = new List<ISearchQueryFilter>(); 8 9 input = input.Trim(); 10 if (input.Length == 0) return []; 11 12 int pos = 0; 13 while (pos < input.Length) 14 { 15 var oldPos = pos; 16 var res = ParseToken(input, ref pos); 17 if (res == null) return results; 18 if (pos <= oldPos) throw new Exception("Infinite loop detected!"); 19 results.Add(res); 20 } 21 22 return results; 23 } 24 25 private static ISearchQueryFilter? ParseToken(ReadOnlySpan<char> input, ref int pos) 26 { 27 while (input[pos] == ' ') 28 { 29 pos++; 30 if (pos >= input.Length) return null; 31 } 32 33 var negated = false; 34 if (input[pos] == '-' && input.Length > pos + 1) 35 { 36 negated = true; 37 pos++; 38 } 39 40 if (input[pos] == '"' && input.Length > pos + 2) 41 { 42 var closingQuote = pos + 1 + input[(pos + 1)..].IndexOf('"'); 43 if (closingQuote != -1) 44 { 45 var literalRes = new WordFilter(negated, input[++pos..closingQuote].ToString()); 46 pos = closingQuote + 1; 47 return literalRes; 48 } 49 } 50 51 if (input[pos] == '(' && input.Length > pos + 2) 52 { 53 var closingParen = pos + 1 + input[(pos + 1)..].IndexOf(')'); 54 if (closingParen != -1) 55 { 56 var items = input[++pos..closingParen].ToString().Split(" OR ").Select(p => p.Trim()).ToArray(); 57 var literalRes = new MultiWordFilter(negated, items); 58 if (items.Length > 0) 59 { 60 pos = closingParen + 1; 61 return literalRes; 62 } 63 } 64 } 65 66 var end = input[pos..].IndexOf(' '); 67 if (end == -1) 68 end = input.Length; 69 else 70 end += pos; 71 72 var splitIdx = input[pos..end].IndexOf(':'); 73 var keyRange = splitIdx < 1 ? ..0 : pos..(pos + splitIdx); 74 var key = splitIdx < 1 ? ReadOnlySpan<char>.Empty : input[keyRange]; 75 var value = splitIdx < 1 ? input : input[(keyRange.End.Value + 1)..end]; 76 77 ISearchQueryFilter res = key switch 78 { 79 "cw" => new CwFilter(negated, value.ToString()), 80 "from" or "author" or "by" or "user" => new FromFilter(negated, value.ToString()), 81 "mention" or "mentions" or "mentioning" => new MentionFilter(negated, value.ToString()), 82 "reply" or "replying" or "to" => new ReplyFilter(negated, value.ToString()), 83 "instance" or "domain" or "host" => new InstanceFilter(negated, value.ToString()), 84 85 "filter" when MiscFilter.TryParse(negated, value, out var parsed) => parsed, 86 "in" when InFilter.TryParse(negated, value, out var parsed) => parsed, 87 "visibility" when VisibilityFilter.TryParse(negated, value, out var parsed) => parsed, 88 "has" or "attachment" or "attached" when AttachmentFilter.TryParse(negated, value, out var parsed) 89 => parsed, 90 91 "case" when CaseFilter.TryParse(value, out var parsed) => parsed, 92 "match" when MatchFilter.TryParse(value, out var parsed) => parsed, 93 94 "after" or "since" when DateOnly.TryParse(value, out var date) => new AfterFilter(date), 95 "before" or "until" when DateOnly.TryParse(value, out var date) => new BeforeFilter(date), 96 97 _ => new WordFilter(negated, input[pos..end].ToString()) 98 }; 99 100 pos = end; 101 return res; 102 } 103}