Skip to content

Conversation

@HowardvanRooijen
Copy link
Member

I merged both fixes into a single branch, build the solution and installed the cshap-lsp global tool into the dev container and configured the claude code csharp-lsp. I managed to invoke it and got it to interrogate a project I'm working on:

Server Capabilities (from Initialize Response)

The server reports the following capabilities during LSP handshake:
┌───────────────────────┬───────────┬─────────────────────────────────────────────────┐
│      Capability       │ Supported │                     Details                     │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Text Document Sync    │ ✅        │ Open/close, incremental changes, save with text │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Completion            │ ✅        │ Triggers: ., ' with resolve support             │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Hover                 │ ✅        │ Markdown and plaintext content                  │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Signature Help        │ ✅        │ Triggers: (, ,, <, {, [                         │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Go to Definition      │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Go to Type Definition │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Go to Implementation  │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Find References       │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Document Highlight    │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Document Symbols      │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Code Actions          │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Code Lens             │ ✅        │ With resolve support                            │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Workspace Symbols     │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Document Formatting   │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Range Formatting      │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ On-Type Formatting    │ ✅        │ Triggers: ;, }, )                               │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Rename                │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Call Hierarchy        │ ✅        │                                                 │
├───────────────────────┼───────────┼─────────────────────────────────────────────────┤
│ Semantic Tokens       │ ✅        │ Full token legend                               │
└───────────────────────┴───────────┴─────────────────────────────────────────────────┘
---
Tested Features

1. Hover Information (textDocument/hover)

Request: Position on LoadCommand class name (line 21, character 20)

Response:
```csharp
LoadCommand

Loads a document or directory of documents into the RLM session for processing.
Supports multiple formats: Markdown, PDF, HTML, JSON, Word (.docx), and plain text.

**Capabilities Demonstrated:**
- Returns XML documentation comments
- Markdown formatted output
- Type name with syntax highlighting

---

### 2. Go to Definition (`textDocument/definition`)

**Request:** Position on `CompositeDocumentReader` (line 44, character 12)

**Response:**
```json
{
  "uri": "file://.../Rlm.Cli/Core/Documents/CompositeDocumentReader.cs",
  "range": {
    "start": { "line": 12, "character": 20 },
    "end": { "line": 12, "character": 43 }
  }
}

Capabilities Demonstrated:
- Cross-file navigation
- Precise location (line and character range)
- Resolves to class definition

---
3. Find All References (textDocument/references)

Request: Position on RlmSession (line 80, character 10)

Response: Found 223 references across the codebase

Sample locations:
┌───────────────────┬─────────────────┐
│       File        │      Line       │
├───────────────────┼─────────────────┤
│ RlmSession.cs     │ 12 (definition) │
├───────────────────┼─────────────────┤
│ StoreCommand.cs   │ 30              │
├───────────────────┼─────────────────┤
│ FilterCommand.cs  │ 35              │
├───────────────────┼─────────────────┤
│ LoadCommand.cs    │ 79              │
├───────────────────┼─────────────────┤
│ RlmJsonContext.cs │ 20              │
├───────────────────┼─────────────────┤
│ ...and 218 more   │                 │
└───────────────────┴─────────────────┘
Capabilities Demonstrated:
- Cross-file reference finding
- Includes declaration
- Searches entire solution

---
4. Code Completion (textDocument/completion)

Request: After session. (line 81, character 16)

Response: Incomplete list with members of RlmSession:
┌─────────────────────────┬──────────┬─────────────┐
│          Label          │   Kind   │ Description │
├─────────────────────────┼──────────┼─────────────┤
│ ChunkBuffer             │ Property │             │
├─────────────────────────┼──────────┼─────────────┤
│ Clear                   │ Method   │             │
├─────────────────────────┼──────────┼─────────────┤
│ Content                 │ Property │             │
├─────────────────────────┼──────────┼─────────────┤
│ CurrentChunk            │ Property │             │
├─────────────────────────┼──────────┼─────────────┤
│ CurrentChunkIndex       │ Property │             │
├─────────────────────────┼──────────┼─────────────┤
│ DecrementRecursionDepth │ Method   │             │
├─────────────────────────┼──────────┼─────────────┤
│ Equals                  │ Method   │ (inherited) │
├─────────────────────────┼──────────┼─────────────┤
│ ...more                 │          │             │
└─────────────────────────┴──────────┴─────────────┘
Capabilities Demonstrated:
- Context-aware completions
- Member kind identification (Property=10, Method=2)
- Supports resolve for additional details
- Incremental completion (isIncomplete: true)

---
5. Document Symbols (textDocument/documentSymbol)

Request: Full document structure for LoadCommand.cs

Response: Hierarchical symbol tree:

📄 LoadCommand.cs (File)
└── 📦 Rlm.Cli.Commands (Namespace)
    └── 📦 LoadCommand (Class)
        ├── 📦 Settings (Class)
        │   ├── 🔷 Source (Property) - string
        │   ├── 🔷 Pattern (Property) - string?
        │   └── 🔷 Merge (Property) - bool
        ├── 🔷 ExecuteAsync (Method)
        ├── 🔷 LoadSingleFileAsync (Method)
        ├── 🔷 LoadDirectoryAsync (Method)
        ├── 🔷 MergeDocuments (Method)
        ├── 🔷 DisplayDocumentInfo (Method)
        └── 🔷 CreateCompositeReader (Method)

Capabilities Demonstrated:
- Nested class support
- Property type information in detail field
- Range and selection range for each symbol
- Symbol kinds: File(1), Namespace(3), Class(5), Property(7), Method(6)

---
6. Real-time Diagnostics (textDocument/publishDiagnostics)

Test: Introduced syntax error UNDEFINED_VAR

Response:
{
  "uri": "file://.../LoadCommand.cs",
  "diagnostics": [{
    "range": {
      "start": { "line": 40, "character": 30 },
      "end": { "line": 40, "character": 43 }
    },
    "severity": 1,
    "code": "CS0103",
    "codeDescription": {
      "href": "https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS0103)"
    },
    "source": "lsp",
    "message": "The name 'UNDEFINED_VAR' does not exist in the current context"
  }]
}

Capabilities Demonstrated:
- Real-time error detection on document change
- Precise error location
- C# compiler error codes (CS0103, CS0029, CS0246, etc.)
- Links to documentation
- Severity levels (1 = Error)

---
Additional Tested Error Types
┌────────────┬──────────┬──────────────────────────────┐
│ Error Code │   Type   │           Message            │
├────────────┼──────────┼──────────────────────────────┤
│ CS0103     │ Semantic │ Undefined variable           │
├────────────┼──────────┼──────────────────────────────┤
│ CS0029     │ Type     │ Cannot convert string to int │
├────────────┼──────────┼──────────────────────────────┤
│ CS0246     │ Type     │ Undefined type/class         │
└────────────┴──────────┴──────────────────────────────┘
---
Solution Loading

Capabilities:
- Auto-discovers .sln files in workspace
- Supports explicit --solution flag
- Registers MSBuild SDK (.NET 10.0.101)
- Loads all projects in solution

Log Output:
SDK instances found: .NET Core SDK, Version=10.0.101
MSBuildLocator: will register ".NET Core SDK" as default instance
Using workspaceFolders: file:///workspaces/.../Solutions

---
Performance Notes
┌──────────────────────────┬──────────────────────┐
│        Operation         │       Latency        │
├──────────────────────────┼──────────────────────┤
│ Initialize               │ ~200ms               │
├──────────────────────────┼──────────────────────┤
│ Solution Load            │ ~10-12s (first time) │
├──────────────────────────┼──────────────────────┤
│ Hover                    │ <100ms               │
├──────────────────────────┼──────────────────────┤
│ Definition               │ <100ms               │
├──────────────────────────┼──────────────────────┤
│ References (223 results) │ ~2s                  │
├──────────────────────────┼──────────────────────┤
│ Completion               │ <500ms               │
├──────────────────────────┼──────────────────────┤
│ Diagnostics (on change)  │ ~1-2s                │
└──────────────────────────┴──────────────────────┘
---
Summary

The csharp-ls language server provides comprehensive C# language support including:

✅ Navigation: Definition, type definition, implementation, references
✅ Intelligence: Hover docs, completion, signature help
✅ Analysis: Real-time diagnostics, semantic tokens
✅ Refactoring: Rename, code actions, formatting
✅ Structure: Document symbols, workspace symbols, call hierarchy
✅ Roslyn-powered: Full C# semantic analysis via .NET compiler platform

  1. Removed unsafe .Value call (line 455) - The original code accessed wf.Value before the match to check if wf was Some. This caused crashes when the workspace folder wasn't found.
  2. Moved wfPathToUri into the Some wf, Some doc branch (line 510) - The calculation now only happens when we're certain wf is Some.
  3. Added .cshtml extension check (line 460) - The Some wf, None branch now only processes files as Razor/cshtml if they actually have a .cshtml extension, instead of treating ALL unfound documents as cshtml files.
  4. Safe handling of wf.Solution (lines 461-466) - Instead of the unsafe wf.Solution.Value, the code now pattern matches on wf.Solution to safely handle the case where the solution hasn't loaded yet.
  5. Added retry logic for unfound documents (lines 464-465, 504-505) - When a document isn't found (due to timing or solution not being fully loaded), the code now posts PushDiagnosticsDocumentBacklogUpdate and PushDiagnosticsProcessPendingDocuments to rebuild the backlog and
  retry later.
  6. Added continuation for unfound .cshtml documents (line 495) - When a .cshtml document isn't found as a Razor document, processing continues with the next document.

  All 67 tests pass, including the two previously failing tests:
  - testPushDiagnosticsWork
  - testDiagnoseCommandWorks
Copilot AI review requested due to automatic review settings January 23, 2026 18:44
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes test failures on main and addresses issue razzmatazz#306 by improving error handling in the ProgressReporter and fixing a critical bug in ServerState's diagnostic processing logic. The PR also adds comprehensive unit tests for the ProgressReporter to ensure exceptions from unsupported client methods are handled gracefully.

Changes:

  • Added exception handling in ProgressReporter.Begin to gracefully handle clients that don't support window/workDoneProgress/create
  • Fixed a bug in ServerState where wf.Value was accessed before null checking, which could cause exceptions
  • Improved .cshtml file handling with explicit extension checking and solution loading state management
  • Added comprehensive unit tests for ProgressReporter error handling scenarios

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
tests/CSharpLanguageServer.Tests/ProgressReporterTests.fs New test file validating exception handling in ProgressReporter
tests/CSharpLanguageServer.Tests/CSharpLanguageServer.Tests.fsproj Added reference to new ProgressReporterTests.fs file
src/CSharpLanguageServer/Lsp/ProgressReporter.fs Added try-catch to handle exceptions from clients that don't support progress reporting
src/CSharpLanguageServer/State/ServerState.fs Fixed unsafe Option.Value access, added .cshtml extension check, and improved retry logic for unloaded solutions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…eporting

Checks the client's window.workDoneProgress capability before
attempting to create progress tokens. If the capability is not advertised or is
false, progress reporting is silently skipped.

Changes:
- ProgressReporter.fs: Add ClientCapabilities parameter to constructor;
check Window.WorkDoneProgress capability before calling
WindowWorkDoneProgressCreate; remove try-catch exception handling
- Workspace.fs: Pass ClientCapabilities to ProgressReporter
- ServerState.fs: Pass state.ClientCapabilities to workspace loading
- Diagnostics.fs: Pass emptyClientCapabilities to ProgressReporter
- Tooling.fs: Add Window.WorkDoneProgress = true to test client capabilities
- ProgressReporterTests.fs: Replace exception-based tests with capability-based
tests that verify WindowWorkDoneProgressCreate is only called when supported
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants