diff --git a/QuickShell.Core/Services/RootPaletteSearchIndex.cs b/QuickShell.Core/Services/RootPaletteSearchIndex.cs index 98f3fbe5..1d589ac6 100644 --- a/QuickShell.Core/Services/RootPaletteSearchIndex.cs +++ b/QuickShell.Core/Services/RootPaletteSearchIndex.cs @@ -285,6 +285,7 @@ private static int ScoreToken(string? value, string token, int exact, int prefix return value.Contains(token, StringComparison.OrdinalIgnoreCase) ? contains : 0; } + // Bolt: Performance optimization - avoid string[] allocations by using SplitAny over ReadOnlySpan private static string[] GetTaskSearchTokens(string? query) { if (string.IsNullOrWhiteSpace(query)) @@ -292,18 +293,23 @@ private static string[] GetTaskSearchTokens(string? query) return []; } - return query - .Split([' ', '\t', '\r', '\n'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) - .Select(NormalizeTaskSearchToken) - .Where(token => token.Length > 0 && !IsTaskSearchVerb(token)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); + var tokens = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var range in query.AsSpan().SplitAny([' ', '\t', '\r', '\n'])) + { + var tokenSpan = NormalizeTaskSearchToken(query.AsSpan(range).Trim()); + if (tokenSpan.Length > 0 && !IsTaskSearchVerb(tokenSpan)) + { + tokens.Add(tokenSpan.ToString()); + } + } + + return tokens.ToArray(); } - private static string NormalizeTaskSearchToken(string token) => - token.Trim('\'', '"', '`', ',', '.', ':', ';', '(', ')', '[', ']', '{', '}'); + private static ReadOnlySpan NormalizeTaskSearchToken(ReadOnlySpan token) => + token.Trim("'\"`,.:;()[]{}".AsSpan()); - private static bool IsTaskSearchVerb(string token) => + private static bool IsTaskSearchVerb(ReadOnlySpan token) => token.Equals("run", StringComparison.OrdinalIgnoreCase) || token.Equals("open", StringComparison.OrdinalIgnoreCase) || token.Equals("start", StringComparison.OrdinalIgnoreCase) || diff --git a/QuickShell.Core/Services/WorkspaceRepositorySnapshot.cs b/QuickShell.Core/Services/WorkspaceRepositorySnapshot.cs index 8e85758d..40517cd6 100644 --- a/QuickShell.Core/Services/WorkspaceRepositorySnapshot.cs +++ b/QuickShell.Core/Services/WorkspaceRepositorySnapshot.cs @@ -288,6 +288,7 @@ private static int ScoreToken(string? value, string token, int exact, int prefix return trimmed.Contains(token, StringComparison.OrdinalIgnoreCase) ? contains : 0; } + // Bolt: Performance optimization - avoid string[] allocations by using SplitAny over ReadOnlySpan private static string[] GetTaskSearchTokens(string? query) { if (string.IsNullOrWhiteSpace(query)) @@ -295,18 +296,23 @@ private static string[] GetTaskSearchTokens(string? query) return []; } - return query - .Split([' ', '\t', '\r', '\n'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) - .Select(NormalizeTaskSearchToken) - .Where(token => token.Length > 0 && !IsTaskSearchVerb(token)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); + var tokens = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var range in query.AsSpan().SplitAny([' ', '\t', '\r', '\n'])) + { + var tokenSpan = NormalizeTaskSearchToken(query.AsSpan(range).Trim()); + if (tokenSpan.Length > 0 && !IsTaskSearchVerb(tokenSpan)) + { + tokens.Add(tokenSpan.ToString()); + } + } + + return tokens.ToArray(); } - private static string NormalizeTaskSearchToken(string token) => - token.Trim('\'', '"', '`', ',', '.', ':', ';', '(', ')', '[', ']', '{', '}'); + private static ReadOnlySpan NormalizeTaskSearchToken(ReadOnlySpan token) => + token.Trim("'\"`,.:;()[]{}".AsSpan()); - private static bool IsTaskSearchVerb(string token) => + private static bool IsTaskSearchVerb(ReadOnlySpan token) => token.Equals("run", StringComparison.OrdinalIgnoreCase) || token.Equals("open", StringComparison.OrdinalIgnoreCase) || token.Equals("start", StringComparison.OrdinalIgnoreCase) ||