Forge
csharpdeeb25a2
1using System.IO;
2using System.Threading;
3using System.Threading.Tasks;
4using Avalonia.Threading;
5using CascadeIDE.Features.Lsp.DataAcquisition;
6using CascadeIDE.Features.Editor.Application.Monaco;
7using CascadeIDE.Services.Lsp;
8
9namespace CascadeIDE.ViewModels;
10
11/// <summary>Запуск/перезапуск C# LSP.</summary>
12public partial class MainWindowViewModel
13{
14 /// <summary>Варианты C# LSP (настройки; активен не более одного процесса).</summary>
15 public IReadOnlyList<string> CSharpLspProviderOptionsList => CSharpLspProviderIds.All;
16
17 public bool IsCSharpLspProcessSelected =>
18 !string.Equals(_csharpLspProvider, CSharpLspProviderIds.ParseOnly, StringComparison.OrdinalIgnoreCase);
19
20 private string _csharpLspProvider = CSharpLspProviderIds.ParseOnly;
21 private string _csharpLspExecutable = "";
22 private string _csharpLspArguments = "";
23
24 /// <summary><see cref="CSharpLspProviderIds"/>.</summary>
25 public string CSharpLspProvider
26 {
27 get => _csharpLspProvider;
28 set
29 {
30 var v = string.IsNullOrWhiteSpace(value) ? CSharpLspProviderIds.ParseOnly : value.Trim();
31 if (!SetProperty(ref _csharpLspProvider, v))
32 return;
33 _settings.Languages.CSharp.SetMode(v);
34 SaveSettingsIfChanged();
35 OnPropertyChanged(nameof(IsCSharpLspProcessSelected));
36 _ = RestartCSharpLanguageServerAsync();
37 }
38 }
39
40 public string CSharpLspExecutable
41 {
42 get => _csharpLspExecutable;
43 set
44 {
45 var v = value ?? "";
46 if (!SetProperty(ref _csharpLspExecutable, v))
47 return;
48 _settings.Languages.CSharp.SetLaunchOverrides(_csharpLspProvider, v, _csharpLspArguments);
49 SaveSettingsIfChanged();
50 _ = RestartCSharpLanguageServerAsync();
51 }
52 }
53
54 public string CSharpLspArguments
55 {
56 get => _csharpLspArguments;
57 set
58 {
59 var v = value ?? "";
60 if (!SetProperty(ref _csharpLspArguments, v))
61 return;
62 _settings.Languages.CSharp.SetLaunchOverrides(_csharpLspProvider, _csharpLspExecutable, v);
63 SaveSettingsIfChanged();
64 _ = RestartCSharpLanguageServerAsync();
65 }
66 }
67
68 private async Task RestartCSharpLanguageServerAsync()
69 {
70 try
71 {
72 var snap = await UiScheduler.Default.InvokeAsync(() =>
73 {
74 _workspaceDiagnostics.SetLspDiagnosticsHost(null);
75 _csharpLspHost?.Dispose();
76 _csharpLspHost = null;
77 var csharpLsp = _settings.Languages.CSharp.ResolveForRuntime();
78 return (
79 Workspace.SolutionPath ?? "",
80 csharpLsp.Mode,
81 csharpLsp.Executable,
82 csharpLsp.Arguments);
83 });
84
85 if (string.Equals(snap.Item2, CSharpLspProviderIds.ParseOnly, StringComparison.OrdinalIgnoreCase))
86 return;
87 if (string.IsNullOrWhiteSpace(snap.Item1) || !File.Exists(snap.Item1))
88 return;
89
90 var host = new CSharpLspDiagnosticsHost();
91 var ok = await host.TryStartAsync(snap.Item2, snap.Item1, snap.Item3, snap.Item4, CancellationToken.None)
92 .ConfigureAwait(false);
93
94 await UiScheduler.Default.InvokeAsync(() =>
95 {
96 if (!ok)
97 {
98 host.Dispose();
99 return;
100 }
101
102 _csharpLspHost = host;
103 _workspaceDiagnostics.SetLspDiagnosticsHost(host);
104 foreach (var d in Documents.OpenDocuments)
105 {
106 if (d.FilePath.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
107 host.EnsureOpened(d.FilePath, d.Content ?? "");
108 }
109 });
110 }
111 finally
112 {
113 await UiScheduler.Default.InvokeAsync(PublishIdeHostLspToDataBusAndRebuild);
114 }
115 }
116
117 /// <summary>Текст Quick Info для тултипа: при активном C# LSP — <c>textDocument/hover</c>, иначе in-process Roslyn.</summary>
118 public async Task<string?> GetEditorQuickInfoAsync(string filePath, string sourceText, int line, int column, CancellationToken ct = default)
119 {
120 if (_csharpLspHost is { IsActive: true })
121 {
122 try
123 {
124 var h = await _csharpLspHost.RequestHoverAsync(filePath, sourceText, line, column, ct).ConfigureAwait(false);
125 if (!string.IsNullOrWhiteSpace(h))
126 return h.Trim();
127 }
128 catch
129 {
130 // fallback: Roslyn
131 }
132 }
133
134 return CSharpLanguage.GetQuickInfo(filePath, sourceText, line, column, ct);
135 }
136
137 internal CSharpLspDiagnosticsHost? CSharpLspHost => _csharpLspHost;
138
139 internal bool TryNavigateCodeLens(string lensId)
140 {
141 var payload = MonacoEditorCodeLensComposer.TryResolveNavigation(
142 lensId,
143 NavigationMap.CodeNavigationMapGraphScene);
144 if (payload is null)
145 return false;
146
147 EditorNavigation.TryNavigateGoTo(
148 payload.FullPath,
149 payload.LineStart ?? 1,
150 1,
151 payload.LineEnd,
152 source: EditorNavigationSource.NavigationMap);
153 return true;
154 }
155}
156
View only · write via MCP/CIDE