anshdadhich commited on
Commit
4860520
·
verified ·
1 Parent(s): 70d9fc3

Upload FastSeekWpf/Core/SearchEngine.cs

Browse files
Files changed (1) hide show
  1. FastSeekWpf/Core/SearchEngine.cs +194 -0
FastSeekWpf/Core/SearchEngine.cs ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.IO;
4
+ using System.Linq;
5
+ using System.Threading.Tasks;
6
+
7
+ namespace FastSeekWpf.Core;
8
+
9
+ public enum ResultKind
10
+ {
11
+ App, Document, Image, Video, Audio, Archive, Folder, Other
12
+ }
13
+
14
+ public class SearchResult
15
+ {
16
+ public string FullPath { get; set; } = string.Empty;
17
+ public string Name { get; set; } = string.Empty;
18
+ public byte Rank { get; set; }
19
+ public bool IsDir { get; set; }
20
+ public ResultKind Kind { get; set; }
21
+ }
22
+
23
+ public static class SearchEngine
24
+ {
25
+ private static readonly string[] AppExtensions = { "exe", "lnk", "msi", "appx", "msix" };
26
+ private static readonly string[] AppPathMarkers = {
27
+ "\\program files\\", "\\program files (x86)\\",
28
+ "\\start menu\\", "\\desktop\\", "\\appdata\\"
29
+ };
30
+
31
+ private static readonly Dictionary<string, ResultKind> ExtensionMap = new(StringComparer.OrdinalIgnoreCase)
32
+ {
33
+ ["exe"] = ResultKind.App, ["lnk"] = ResultKind.App, ["msi"] = ResultKind.App,
34
+ ["doc"] = ResultKind.Document, ["docx"] = ResultKind.Document, ["pdf"] = ResultKind.Document,
35
+ ["txt"] = ResultKind.Document, ["xlsx"] = ResultKind.Document, ["xls"] = ResultKind.Document,
36
+ ["pptx"] = ResultKind.Document, ["ppt"] = ResultKind.Document, ["odt"] = ResultKind.Document,
37
+ ["ods"] = ResultKind.Document, ["odp"] = ResultKind.Document, ["rtf"] = ResultKind.Document,
38
+ ["md"] = ResultKind.Document, ["csv"] = ResultKind.Document, ["json"] = ResultKind.Document,
39
+ ["xml"] = ResultKind.Document, ["yaml"] = ResultKind.Document, ["toml"] = ResultKind.Document,
40
+ ["ini"] = ResultKind.Document, ["log"] = ResultKind.Document,
41
+ ["png"] = ResultKind.Image, ["jpg"] = ResultKind.Image, ["jpeg"] = ResultKind.Image,
42
+ ["gif"] = ResultKind.Image, ["bmp"] = ResultKind.Image, ["webp"] = ResultKind.Image,
43
+ ["svg"] = ResultKind.Image, ["ico"] = ResultKind.Image, ["tiff"] = ResultKind.Image,
44
+ ["heic"] = ResultKind.Image, ["raw"] = ResultKind.Image, ["psd"] = ResultKind.Image,
45
+ ["mp4"] = ResultKind.Video, ["mkv"] = ResultKind.Video, ["avi"] = ResultKind.Video,
46
+ ["mov"] = ResultKind.Video, ["wmv"] = ResultKind.Video, ["flv"] = ResultKind.Video,
47
+ ["webm"] = ResultKind.Video, ["m4v"] = ResultKind.Video,
48
+ ["mp3"] = ResultKind.Audio, ["flac"] = ResultKind.Audio, ["wav"] = ResultKind.Audio,
49
+ ["aac"] = ResultKind.Audio, ["ogg"] = ResultKind.Audio, ["m4a"] = ResultKind.Audio,
50
+ ["wma"] = ResultKind.Audio, ["opus"] = ResultKind.Audio,
51
+ ["zip"] = ResultKind.Archive, ["rar"] = ResultKind.Archive, ["7z"] = ResultKind.Archive,
52
+ ["tar"] = ResultKind.Archive, ["gz"] = ResultKind.Archive, ["bz2"] = ResultKind.Archive,
53
+ ["xz"] = ResultKind.Archive, ["zst"] = ResultKind.Archive,
54
+ };
55
+
56
+ public static ResultKind GetKind(string? ext, bool isDir, string fullPathLower)
57
+ {
58
+ if (isDir) return ResultKind.Folder;
59
+ if (ext == null) return ResultKind.Other;
60
+ if (ExtensionMap.TryGetValue(ext, out var kind))
61
+ {
62
+ if (kind == ResultKind.App && AppPathMarkers.Any(m => fullPathLower.Contains(m)))
63
+ return ResultKind.App;
64
+ return kind;
65
+ }
66
+ return ResultKind.Other;
67
+ }
68
+
69
+ public static List<SearchResult> Search(
70
+ IndexStore store,
71
+ string query,
72
+ int limit,
73
+ bool caseSensitive,
74
+ List<string> excludedDirs)
75
+ {
76
+ if (string.IsNullOrWhiteSpace(query))
77
+ return new List<SearchResult>();
78
+
79
+ string q = caseSensitive ? query : query.ToLowerInvariant();
80
+
81
+ var candidates = new List<(int idx, byte rank)>();
82
+ lock (store)
83
+ {
84
+ for (int i = 0; i < store.Entries.Count; i++)
85
+ {
86
+ var entry = store.Entries[i];
87
+ string name = caseSensitive ? store.Name(entry) : store.NameLower(entry);
88
+
89
+ byte rank;
90
+ if (name == q) rank = 1;
91
+ else if (name.StartsWith(q, StringComparison.Ordinal)) rank = 2;
92
+ else if (name.Contains(q, StringComparison.Ordinal)) rank = 3;
93
+ else continue;
94
+
95
+ candidates.Add((i, rank));
96
+ }
97
+ }
98
+
99
+ candidates.Sort((a, b) => a.rank.CompareTo(b.rank));
100
+ int overshoot = Math.Max(limit * 5, 1000);
101
+ if (candidates.Count > overshoot)
102
+ candidates.RemoveRange(overshoot, candidates.Count - overshoot);
103
+
104
+ var results = new List<SearchResult>(Math.Min(limit, candidates.Count));
105
+
106
+ foreach (var (idx, baseRank) in candidates)
107
+ {
108
+ var entry = store.Entries[idx];
109
+ string fullPath = store.BuildPath(entry.FileRef);
110
+ string fullPathLower = fullPath.ToLowerInvariant();
111
+
112
+ if (excludedDirs.Count > 0 && excludedDirs.Any(ex => fullPathLower.StartsWith(ex, StringComparison.Ordinal)))
113
+ continue;
114
+
115
+ string name = store.Name(entry);
116
+ string nameLower = store.NameLower(entry);
117
+
118
+ byte rank = baseRank;
119
+ if (baseRank <= 2)
120
+ {
121
+ int dotIdx = nameLower.LastIndexOf('.');
122
+ if (dotIdx >= 0)
123
+ {
124
+ string ext = nameLower[(dotIdx + 1)..];
125
+ if (AppExtensions.Contains(ext) && AppPathMarkers.Any(m => fullPathLower.Contains(m)))
126
+ rank = 0;
127
+ }
128
+ }
129
+
130
+ string? fileExt = null;
131
+ if (!entry.IsDir)
132
+ {
133
+ int dot = name.LastIndexOf('.');
134
+ if (dot >= 0) fileExt = name[(dot + 1)..].ToLowerInvariant();
135
+ }
136
+
137
+ results.Add(new SearchResult
138
+ {
139
+ FullPath = fullPath,
140
+ Name = name,
141
+ Rank = rank,
142
+ IsDir = entry.IsDir,
143
+ Kind = GetKind(fileExt, entry.IsDir, fullPathLower)
144
+ });
145
+ }
146
+
147
+ results.Sort((a, b) => a.Rank.CompareTo(b.Rank));
148
+ if (results.Count > limit)
149
+ results.RemoveRange(limit, results.Count - limit);
150
+
151
+ return results;
152
+ }
153
+
154
+ public static List<SearchResult> SearchByExtension(
155
+ IndexStore store,
156
+ string ext,
157
+ List<string> excludedDirs)
158
+ {
159
+ string dotExt = "." + ext.ToLowerInvariant();
160
+ var results = new List<SearchResult>();
161
+
162
+ lock (store)
163
+ {
164
+ foreach (var entry in store.Entries)
165
+ {
166
+ string name = store.NameLower(entry);
167
+ if (!name.EndsWith(dotExt)) continue;
168
+
169
+ string fullPath = store.BuildPath(entry.FileRef);
170
+ string fullPathLower = fullPath.ToLowerInvariant();
171
+
172
+ if (excludedDirs.Any(ex => fullPathLower.StartsWith(ex, StringComparison.Ordinal)))
173
+ continue;
174
+
175
+ string? fileExt = null;
176
+ int dot = name.LastIndexOf('.');
177
+ if (dot >= 0) fileExt = name[(dot + 1)..];
178
+
179
+ results.Add(new SearchResult
180
+ {
181
+ FullPath = fullPath,
182
+ Name = store.Name(entry),
183
+ Rank = 0,
184
+ IsDir = entry.IsDir,
185
+ Kind = GetKind(fileExt, entry.IsDir, fullPathLower)
186
+ });
187
+
188
+ if (results.Count >= 50) break;
189
+ }
190
+ }
191
+
192
+ return results;
193
+ }
194
+ }