| 1 | # План: языковые сервисы C# (гибридный подход) |
| 2 | |
| 3 | Зафиксировано решение использовать **вариант C — гибрид**: in-process Roslyn для быстрых сценариев, LSP (OmniSharp) для полного решения. |
| 4 | |
| 5 | ## Цель |
| 6 | |
| 7 | - **Отзывчивость:** ввод и простые действия не ждут поднятия внешнего процесса. |
| 8 | - **Полнота по решению:** диагностика, Go to Definition, Find References, рефакторинги по всему решению — без собственного MSBuildWorkspace, за счёт готового language server. |
| 9 | |
| 10 | ## Текущее состояние (база) |
| 11 | |
| 12 | - **In-process Roslyn** (один файл, кэш): |
| 13 | - `CSharpLanguageService`: completion (члены после `.`, ключевые слова, LookupSymbols), signature help, подсветка вхождений в текущем файле. |
| 14 | - Кэш по (path, textHash, line, column); сброс при смене файла/решения. |
| 15 | - `EditorIntelligence`: триггеры (`.` / Ctrl+Space), debounce, Popup для completion и signature, IBackgroundRenderer для highlight вхождений в текущем файле (без дублирования диагностик в intelligence). |
| 16 | - **Диагностики по всем открытым `.cs`:** `WorkspaceDiagnosticsCoordinator` — debounce ~400 ms, кэш по пути, событие `DiagnosticsChanged`, список для панели Problems (`ProblemsPanelViewModel`). В `CSharpLanguageService.GetDiagnosticsForFile` — **только парсер** (синтаксис/лексика), без семантики однофайловой «скретч»-компиляции, чтобы не было ложных CS0246 при успешном `dotnet build`. |
| 17 | - **Редактор:** на каждой вкладке `DockDocumentView` ставит `EditorDiagnosticBackgroundRenderer` + подписка на координатор (не только активная вкладка); tooltip по наведению на полосу (`HitTest`). |
| 18 | - **LSP (выбор провайдера):** настройки `CSharpLspProvider` (ParseOnly / OmniSharp / CSharpLs / Custom), stdio JSON-RPC, `CSharpLspDiagnosticsHost` + `WorkspaceDiagnosticsCoordinator.SetLspDiagnosticsHost`. Перезапуск при смене решения или настроек. |
| 19 | - **Контракт:** `Services/Lsp/ILspDiagnosticSource.cs`. |
| 20 | - Редактор: AvaloniaEdit, TextMate для подсветки синтаксиса. |
| 21 | - Загрузка решения и файлов — в фоне (LoadSolutionAsync, LoadFileContentAsync). |
| 22 | |
| 23 | ## Этапы плана |
| 24 | |
| 25 | ### Этап 1 — Укрепление текущего in-process (при необходимости) |
| 26 | |
| 27 | - [ ] При желании: расширить completion (например, больше контекстов, фильтрация по вводу). |
| 28 | - [ ] Сохранить текущее поведение: без открытого решения или до старта LSP всё работает как сейчас. |
| 29 | |
| 30 | ### Этап 2 — LSP-клиент в CascadeIDE |
| 31 | |
| 32 | - [ ] Подключить **OmniSharp.Extensions.LanguageClient** (NuGet) для роли LSP-клиента. |
| 33 | - [ ] Запуск **OmniSharp-Roslyn** (или другого C# LSP-сервера) как дочернего процесса при открытии решения (.sln / .csproj); обмен по stdio (JSON-RPC). |
| 34 | - [ ] Инициализация сессии: `initialize` + `initialized`, привязка к корню решения (workspace folder). |
| 35 | - [ ] Отправка документов: при открытии/изменении файла — `textDocument/didOpen`, `textDocument/didChange` и т.д. |
| 36 | |
| 37 | ### Этап 3 — Использование LSP по решению |
| 38 | |
| 39 | - [ ] **Диагностика:** подписка на `textDocument/publishDiagnostics`, отображение подчёркиваний/списка ошибок в редакторе (или панель проблем). |
| 40 | - [ ] **Completion:** при открытом решении и готовом LSP — запрос `textDocument/completion` (можно дублировать или постепенно переключать с in-process на LSP для файлов из решения). |
| 41 | - [ ] **Go to Definition / Find References:** запросы к LSP, навигация по результатам (открытие файла, позиция в редакторе). |
| 42 | - [ ] По желанию: Hover, Signature Help от LSP для файлов решения. |
| 43 | |
| 44 | ### Этап 4 — Правило «когда что» |
| 45 | |
| 46 | - [ ] Чёткое правило: **если открыто решение и LSP запущен и готов — используем LSP** для completion/diagnostics/definition/references по этому решению. |
| 47 | - [ ] **Иначе** (файл без решения, LSP ещё не поднят, ошибка подключения) — только in-process Roslyn (текущая логика). |
| 48 | - [ ] При смене решения — перезапуск LSP (новый процесс на новое решение), сброс кэша in-process. |
| 49 | |
| 50 | ### Этап 5 (опционально) — Отладка (DAP) |
| 51 | |
| 52 | - [x] Встроенная отладка через **netcoredbg** (протокол DAP по stdio): общий клиент в `DotnetDebug.Core` (`DapClient`), сессия в IDE — `Services/IdeDapDebugSession` (паритет с `dotnet-debug-mcp`). |
| 53 | - [x] Команды MCP/IDE: `debug_launch`, `debug_attach`, `debug_continue`, шаги, стек/переменные — см. `IdeCommands` и `IdeMcpCommandExecutor.Handlers.DapDebug.cs`. |
| 54 | - [x] UI: меню **Отладка**, горячие клавиши F5 / Shift+F5 / F10 / F11 / Shift+F11; диалоги выбора цели (.dll/.exe) и PID для attach (`MainWindow.Dialogs.axaml.cs`). |
| 55 | - Примечание: отдельный NuGet **OmniSharp.Extensions.DebugAdapter.Client** не используется — достаточно общего DAP-клиента и netcoredbg, как в MCP. |
| 56 | |
| 57 | ## Зависимости и ссылки |
| 58 | |
| 59 | - **OmniSharp-Roslyn:** https://github.com/OmniSharp/omnisharp-roslyn (C# language server, LSP по stdio). |
| 60 | - **OmniSharp csharp-language-server-protocol:** https://github.com/OmniSharp/csharp-language-server-protocol (LSP на C#; для этапов 2–4). |
| 61 | - **RoslynPad** (внешний ориентир, **не** NuGet-зависимость): https://github.com/roslynpad/roslynpad — продукт на Roslyn + редактор (AvalonEdit / Avalonia), где **уже** есть **autocomplete, code fixes** и сопутствующий набор; у нас аналогичные возможности **только наращиваются**. Смотреть на готовую реализацию того, что у нас **ещё** предстоит довести; не форк и не drop-in для AvaloniaEdit в CascadeIDE. |
| 62 | - **netcoredbg** (внешний процесс): путь через `NETCOREDBG_PATH` или `PATH`; см. также `Financial/software/open/dotnet-debug-mcp`. |
| 63 | |
| 64 | ## Документ |
| 65 | |
| 66 | - Создан: 2026-02. |
| 67 | - Обновлять по мере выполнения этапов и смены приоритетов. |
| 68 | |
| 69 | |