twoslash for C#

Rich, interactive C# code snippets
powered by Roslyn

Add hover tooltips, IntelliSense completions, and compile verification to your C# documentation. Zero runtime JavaScript. Built on the same compiler that powers Visual Studio.

// @noErrors
var todos = new List<Todo>
{
new("Learn Glo#", true),
new("Build docs", false),
};
var pending = todos.Where(t => !t.Done);
//^?
// @highlight
Console.WriteLine($"Pending: {pending.Count()}");
// @hide
/// <summary>A task with a title and completion status.</summary>
public record Todo(string Title, bool Done);
var todos = new List<Todo>
{
    new("Learn Glo#", true),
    new("Build docs", false),
};

var pending = todos.Where(t => !t.Done);
//^?

// @highlight
Console.WriteLine($"Pending: {pending.Count()}");
// @hide
/// <summary>A task with a title and completion status.</summary>
public record Todo(string Title, bool Done);

Compiler-verified

Every snippet is compiled by Roslyn. Catch errors in documentation before your readers do.

IDE-quality hovers

Full type signatures, XML doc comments, parameter info, and overload counts—just like Visual Studio.

Zero runtime JS

Tooltips use CSS anchor positioning. No JavaScript shipped to your readers—ever.

Everything you need for
beautiful C# documentation

^?

Hover queries

Place // ^? markers below any token to show its type signature and documentation inline. Readers see exactly what they'd see in their IDE.

// @noErrors
var items = new List<int> { 1, 2, 3 };
var count = items.Count;
// ^?
var items = new List<int> { 1, 2, 3 };
var count = items.Count;
//  ^?
^?

XML documentation

Full extraction of <summary>, <param>, <returns>, <remarks>, and <exception> tags. Rendered in structured, readable popups.

// @noErrors
var items = new List<int> { 1, 2, 3 };
// ^?
var total = items.Sum();
var items = new List<int> { 1, 2, 3 };
//              ^?
var total = items.Sum();
@errors

Error assertions

Expect specific compiler errors with // @errors: CS1002. Verify error messages and severity. Use // @noErrors to assert clean compilation.

// @errors: CS0029
int x = "hello";
// @errors: CS0029
int x = "hello";
@noErrors

Compile verification

Assert your snippets compile cleanly with // @noErrors. Catch documentation bugs in CI before your readers find them.

// @noErrors
var items = new List<int> { 1, 2, 3 };
var sum = items.Sum();
Console.WriteLine($"Sum: {sum}");
// @noErrors
var items = new List<int> { 1, 2, 3 };
var sum = items.Sum();
Console.WriteLine($"Sum: {sum}");
@highlight

Visual annotations

Highlight, focus, and diff lines with // @highlight, // @focus, and // @diff: +/-. Guide your reader's attention to what matters.

// @suppressErrors
var config = LoadConfig();
var conn = config.GetConnection();
// @highlight
var db = new DbContext(conn);
var config = LoadConfig();
var conn = config.GetConnection();
// @highlight
var db = new DbContext(conn);
#region

Region extraction

Extract named #region blocks from full source files. The entire file compiles for accurate types, but only the region appears in output.

// @suppressErrors
// @hide
public class User {
public string First { get; set; }
public string Last { get; set; }
// @show
public string FullName
=> $"{First} {Last}";
// @hide
}
public class User {
  public string First { get; set; }
  public string Last { get; set; }
  #region FullName
  public string FullName
    => $"{First} {Last}";
  #endregion
}
---cut---

Hidden setup code

Hide boilerplate with // ---cut--- or // @hide/// @show. Setup code compiles but doesn't appear in the rendered snippet.

#:sdk Microsoft.NET.Sdk.Web
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// ---cut---
app.MapGet("/", () => "Hello");
app.Run();
#:sdk Microsoft.NET.Sdk.Web
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// ---cut---
app.MapGet("/", () => "Hello");
app.Run();
#:pkg

File-based apps

On .NET 10+, use #:package and #:sdk directives directly in your code. No separate .csproj needed—your snippet is valid C# and Glo# input.

#:package Newtonsoft.Json@13.0.3
using Newtonsoft.Json;
var json = JsonConvert.SerializeObject(new { x = 1 });
#:package Newtonsoft.Json@13.0.3
using Newtonsoft.Json;
var json = JsonConvert.SerializeObject(new { x = 1 });

Two-layer caching

In-process compilation context cache plus SHA256-keyed disk cache. Rebuilds are fast. Atomic writes handle concurrent processes safely.

Terminal window
$ glosharp verify samples/ --cache-dir .glosharp-cache
24 files verified (18 cached)
Completed in 1.2s

How it works

Glo# runs at build time. Your readers never download extra JavaScript.

1

Write C# with markers

Add // ^? markers to show hover info, // @errors to assert compiler errors, and directives like // @highlight to annotate visually.

2

Roslyn compiles & extracts

Glo# invokes the Roslyn compiler, resolves symbols, extracts type signatures, XML docs, and diagnostics. Everything is output as structured JSON.

3

Render with your tools

Use the Shiki transformer, Expressive Code plugin, or standalone HTML renderer. Hovers become CSS-positioned popups. No JavaScript required.

Works with your stack

First-class integrations for the most popular documentation tools.

Shiki transformer

@glosharp/shiki

Drop into any Shiki-powered pipeline. Works with Astro, VitePress, and any framework that uses Shiki for syntax highlighting.

import { transformerGloSharp } from '@glosharp/shiki'
const html = await codeToHtml(code, {
lang: 'csharp',
transformers: [transformerGloSharp({
project: './My.csproj'
})]
})

Expressive Code plugin

@glosharp/expressive-code

Full Expressive Code integration with auto-hover extraction. Every C# block gets rich tooltips automatically. Perfect for Starlight docs.

import { pluginGloSharp } from '@glosharp/expressive-code'
export default defineConfig({
integrations: [starlight({
expressiveCode: {
plugins: [pluginGloSharp({
project: './My.csproj'
})]
}
})]
})

Standalone HTML

glosharp CLI

Generate self-contained HTML with no external dependencies. Perfect for Hugo, Jekyll, or any static site. Just embed the output.

Terminal window
$ glosharp render snippet.cs \
--theme github-dark \
--standalone \
--output snippet.html

Node.js API

@glosharp/core

Programmatic access for custom integrations. Full TypeScript types. Build your own rendering pipeline or IDE extension.

import { createGloSharp } from '@glosharp/core'
const glosharp = createGloSharp({
project: './My.csproj'
})
const result = await glosharp.process({
code: 'var x = 42; // ^?'
})

Get started in minutes

Pick the integration that fits your workflow.

1. Install the .NET tool and npm packages

Terminal window
dotnet tool install --global GloSharp.Cli
npm install @glosharp/shiki

2. Configure your Astro Shiki setup

astro.config.mjs
import { transformerGloSharp } from '@glosharp/shiki'
export default defineConfig({
markdown: {
shikiConfig: {
transformers: [transformerGloSharp({
project: './samples/Samples.csproj'
})]
}
}
})

3. Write C# code blocks with markers

```csharp
var greeting = "Hello, world!";
greeting.Length;
// ^?
```

1. Install the .NET tool and npm packages

Terminal window
dotnet tool install --global GloSharp.Cli
npm install @glosharp/expressive-code

2. Configure the Expressive Code plugin

astro.config.mjs
import { pluginGloSharp } from '@glosharp/expressive-code'
export default defineConfig({
integrations: [starlight({
expressiveCode: {
plugins: [pluginGloSharp({
project: './samples/Samples.csproj'
})]
}
})]
})

3. Every C# code block is enhanced automatically

With auto-hover extraction, all C# blocks get rich tooltips without any markers. Add // ^? for persistent, always-visible hovers.

1. Install the .NET tool

Terminal window
dotnet tool install --global GloSharp.Cli

2. Process a file

Terminal window
# Output JSON with type info, hovers, errors
glosharp process snippet.cs --project ./My.csproj
# Generate standalone HTML
glosharp render snippet.cs --theme github-dark --standalone
# Process from stdin
echo 'var x = 42; // ^?' | glosharp process --stdin
# Scaffold a config file
glosharp init

1. Add Glo# to your CI pipeline

Terminal window
dotnet tool install --global GloSharp.Cli

2. Verify all snippets compile

Terminal window
# Fail the build if any snippet has unexpected errors
glosharp verify samples/ --project ./Samples.csproj
# With caching for faster CI runs
glosharp verify samples/ --cache-dir .glosharp-cache

Use // @errors: CS0029 to mark expected errors and // @noErrors to assert clean compilation. Unexpected errors will fail the build.

Marker reference

The full set of markers you can use in your C# snippets.

Query markers

// ^? Show type/hover info at this column
// ^| Show IntelliSense completions at this column

Error handling

// @errors: CS1002 Assert specific compiler errors are expected
// @noErrors Assert the snippet compiles cleanly
// @suppressErrors Suppress all or specific error codes

Visual annotations

// @highlight Highlight this line (or a range)
// @focus Focus on this line, dim others
// @diff: + Mark as added line in a diff view
// @diff: - Mark as removed line in a diff view

Visibility

// @hide / // @show Toggle line visibility
// ---cut--- Hide everything above this line
// @above-hidden Alias for ---cut---

Compiler control

// @nullable: enable Set nullable context
// @langVersion: 12 Set C# language version

File-based app directives .NET 10+

#:package Newtonsoft.Json Declare a NuGet package
#:sdk Microsoft.NET.Sdk.Web Set the SDK type
#:property Key=Value Set project properties

Make your C# documentation come alive

Glo# is open source and ready to use today.