Forge
csharpdeeb25a2
1#nullable enable
2
3using CascadeIDE.Features.Chat.AnchorPeek;
4using CascadeIDE.Models.Intercom;
5
6namespace CascadeIDE.Features.Chat;
7
8public partial class ChatPanelViewModel
9{
10 /// <summary>Список якорей выбранного сообщения и черновика (ADR 0128 §10.1).</summary>
11 public string ListAnchorsForSlashContext()
12 {
13 if (IsChatOverviewMode)
14 return "Открой тему (detail): /intercom topic open.";
15
16 var lines = new List<string>();
17
18 if (_pendingAttachDrafts.Count > 0)
19 {
20 lines.Add("Черновик composer:");
21 foreach (var pair in _pendingAttachDrafts.OrderBy(static p => p.Key, StringComparer.OrdinalIgnoreCase))
22 lines.Add(" " + IntercomAnchorSlash.FormatListLine(pair.Value with { Id = pair.Key }));
23 }
24
25 if (SelectedMessageIndex < 0 || SelectedMessageIndex >= ChatMessages.Count)
26 {
27 if (lines.Count > 0)
28 return string.Join(Environment.NewLine, lines) + Environment.NewLine + "Выбери сообщение: /intercom message select <n>.";
29
30 return "Выбери сообщение (/intercom message select <n>) или прикрепи черновик (/attach …).";
31 }
32
33 TryGetFeedOrdinalForMessageIndex(SelectedMessageIndex, out var ordinal);
34 var msg = ChatMessages[SelectedMessageIndex];
35 var attachments = msg.Attachments;
36 if (attachments is null || attachments.Count == 0)
37 {
38 if (lines.Count > 0)
39 return string.Join(Environment.NewLine, lines);
40
41 return $"Сообщение #{ordinal}: вложений нет.";
42 }
43
44 lines.Add($"Сообщение #{ordinal}:");
45 foreach (var anchor in attachments)
46 lines.Add(" " + IntercomAnchorSlash.FormatListLine(anchor, ordinal));
47
48 return string.Join(Environment.NewLine, lines);
49 }
50
51 /// <summary>Reveal по short id без hit-test (ADR 0128 §10.1).</summary>
52 public string PeekAnchorById(string? rawId)
53 {
54 if (!TryResolveAnchorByShortId(rawId, out var anchor, out var messageIndex, out var error))
55 return error;
56
57 _ = RevealAttachmentFromFeedAsync(anchor, select: false, messageIndex);
58 var status = IntercomAnchorSlash.FormatOutcomeShort(anchor.ResolveOutcome);
59 var id = anchor.Id ?? "?";
60 if (AnchorPeekResolver.TryResolve(rawId, BuildAnchorPeekResolveContext(), out _, out _, out var ordinal, out _))
61 return $"Peek #{ordinal} a:{id} ({status}) — открываю в редакторе.";
62
63 return $"Peek a:{id} ({status}) — открываю в редакторе.";
64 }
65
66 private IReadOnlyList<AttachmentAnchor> GetSelectedMessageAttachmentsForSlash()
67 {
68 if (SelectedMessageIndex < 0 || SelectedMessageIndex >= ChatMessages.Count)
69 return [];
70
71 return ChatMessages[SelectedMessageIndex].Attachments ?? [];
72 }
73
74 private AnchorPeekResolveContext BuildAnchorPeekResolveContext()
75 {
76 var all = new List<FeedMessageAnchor>();
77 for (var i = 0; i < ChatMessages.Count; i++)
78 {
79 foreach (var candidate in ChatMessages[i].Attachments ?? [])
80 all.Add(new FeedMessageAnchor(i, candidate));
81 }
82
83 return new AnchorPeekResolveContext(
84 SelectedMessageIndex,
85 GetSelectedMessageAttachmentsForSlash(),
86 _pendingAttachDrafts,
87 all);
88 }
89
90 private bool TryResolveAnchorByShortId(
91 string? rawId,
92 out AttachmentAnchor anchor,
93 out int? messageIndex,
94 out string error)
95 {
96 anchor = new AttachmentAnchor();
97 messageIndex = null;
98 error = "";
99
100 if (AnchorPeekResolver.TryResolve(rawId, BuildAnchorPeekResolveContext(), out anchor, out messageIndex, out _, out error))
101 return true;
102
103 if (IntercomAnchorSlash.TryFormatPeekOrdinalError(rawId, GetSelectedMessageAttachmentsForSlash().Count, out error))
104 return false;
105
106 return false;
107 }
108}
109
View only · write via MCP/CIDE