Forge
csharpdeeb25a2
1#nullable enable
2using CascadeIDE.Features.HybridIndex.Application;
3using CascadeIDE.Models;
4using HybridCodebaseIndex.Core;
5
6namespace CascadeIDE.Features.WorkspaceNavigation.Application;
7
8/// <summary>
9/// Лёгкий FTS-запрос к HCI для строки ориентации у карты намерений (без semantic, малый topN).
10/// </summary>
11public static class SemanticMapHciOrientationAcquirer
12{
13 private const int DefaultTopN = 5;
14
15 /// <summary>Возвращает null, если HCI выключен, нет workspace или нечего искать.</summary>
16 public static async Task<SemanticMapHciOrientationSnapshot?> TryAcquireAsync(
17 IHybridIndexOrchestratorSearch orchestrator,
18 HybridIndexSettings hybridSettings,
19 string workspaceRoot,
20 string? solutionPath,
21 string? currentFilePath,
22 CancellationToken cancellationToken)
23 {
24 if (!hybridSettings.Enabled)
25 return null;
26
27 var root = (workspaceRoot ?? "").Trim();
28 if (string.IsNullOrEmpty(root))
29 return null;
30
31 var query = BuildQueryFromCurrentPath(currentFilePath);
32 if (string.IsNullOrWhiteSpace(query))
33 return null;
34
35 var (hciRoot, hciSln) = HybridIndexScopeResolver.ApplyScopeMode(hybridSettings.ScopeMode, root, solutionPath);
36
37 (SearchResponse response, string? err) = await orchestrator
38 .SearchHybridAsync(
39 hciRoot,
40 hciSln,
41 query,
42 topN: DefaultTopN,
43 pathPrefix: null,
44 excludePathPrefixes: null,
45 extensions: null,
46 semantic: false,
47 alpha: 0.65,
48 beta: 0.35,
49 vecTopK: 30,
50 cancellationToken)
51 .ConfigureAwait(false);
52
53 if (!string.IsNullOrEmpty(err))
54 return new SemanticMapHciOrientationSnapshot([], query, err);
55
56 if (response.Hits.Count == 0)
57 return new SemanticMapHciOrientationSnapshot([], query, null);
58
59 var hits = new List<SemanticMapHciOrientationHit>(response.Hits.Count);
60 foreach (var h in response.Hits)
61 {
62 var leaf = Path.GetFileName((h.Path ?? "").Replace('/', Path.DirectorySeparatorChar));
63 if (string.IsNullOrEmpty(leaf))
64 leaf = h.Path ?? "—";
65 var line = Math.Max(h.LineStart, 1);
66 hits.Add(new SemanticMapHciOrientationHit(leaf, h.HitKind ?? "?", line, h.Snippet ?? ""));
67 }
68
69 return new SemanticMapHciOrientationSnapshot(hits, query, null);
70 }
71
72 internal static string? BuildQueryFromCurrentPath(string? currentFilePath)
73 {
74 if (string.IsNullOrWhiteSpace(currentFilePath))
75 return null;
76 try
77 {
78 var name = Path.GetFileName(currentFilePath.Trim());
79 if (string.IsNullOrEmpty(name))
80 return null;
81 var noExt = Path.GetFileNameWithoutExtension(name);
82 return string.IsNullOrWhiteSpace(noExt) ? name.Trim() : noExt.Trim();
83 }
84 catch
85 {
86 return null;
87 }
88 }
89}
90
View only · write via MCP/CIDE