Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 0 additions & 61 deletions .github/workflows/bump_version.yml

This file was deleted.

11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@
#

*.wasm
/grammars
# Zed's development builds clone declared grammars into `grammars/<id>`;
# those stay ignored, but the vendored Razor grammar source is tracked.
/grammars/*
!/grammars/tree-sitter-razor

#
# Node (vendored grammar tooling)
#

node_modules/

#
# Rust
Expand Down
536 changes: 536 additions & 0 deletions BACKLOG.md

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Changelog

All notable changes to the C# Plus fork are documented here. Each entry that
followed an upstream sync records the merged upstream commit (D0.1 policy).

## Unreleased

### 1.3.0 — Razor editing, workflow, and foundation (Milestone 0 + 1 + 2)

The first fork release. Delivers the Milestone 0 foundation (feasibility,
corpus, fixtures, contract), first-class Razor *editing* (Milestone 1), and the
everyday .NET workflow improvements (Milestone 2). This is editing support, not
full Razor IDE semantics: **no language server starts for Razor buffers in
this release** (see `docs/razor-contract.md`).

#### Added
- Razor language (`Razor`) registered for `.razor` and `.cshtml` with the
pinned `tree-sitter-razor` grammar (M1.1; grammar decision in
`docs/razor-grammar-audit.md`).
- Razor syntax highlighting, HTML/CSS/JS injections, bracket matching,
auto-indentation, outline, and text objects (M1.2, M1.3).
- Razor snippets for common directives and blocks (M1.4).
- Highlight snapshot harness over the committed Razor corpus plus the existing
`csharp` and `msbuild` queries, run in CI on every push (M1.0).
- Discoverable `dotnet` task templates: restore, build, test, run, watch,
clean, publish, format, and EF Core migrations (M2.2).
- Roslyn-first project guidance and actionable diagnostics for the common
failure modes (M2.1).
- Documentation: migration off the upstream C# extension, debugging state,
supported files and known limits (M1.4, M2.3, M2.4).

#### Fork infrastructure (D0.1)
- Replaced upstream's `bump_version` workflow (gated on Zed org ownership and
Zed-internal secrets; could never run in the fork) with the manual
convention in `scripts/bump-version.sh` + `docs/versioning.md`.
- Added the highlight/CI workflow story in `.github/workflows/ci.yml`.
- Recorded upstream sync policy and registry verification in `docs/`.

#### Decisions recorded
- G0 (M0.0 outcome), G1 (M0.2 grammar decision), and the M0.4 opt-in
mechanism are recorded in `BACKLOG.md` and the referenced docs.

## 1.2.2

Fork point: upstream `zed-extensions/csharp` at commit `88597e1` (v1.2.2).
Upstream history before this entry belongs to the upstream project.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "zed_csharp"
name = "zed_csharp_plus"
version = "1.2.2"
edition = "2021"
publish = false
Expand Down
43 changes: 40 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
# Zed C#
# Zed C# Plus

A [C#](https://learn.microsoft.com/en-us/dotnet/csharp/) extension for [Zed](https://zed.dev).
A [C#](https://learn.microsoft.com/en-us/dotnet/csharp/) and
[Razor](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor) extension
for [Zed](https://zed.dev), covering C#, Razor (`.cshtml` / `.razor`), and .NET
project files.

## Provenance

This is a fork of [zed-extensions/csharp](https://github.com/zed-extensions/csharp)
at commit `88597e1` (version 1.2.2), which remains under the Apache-2.0 licence
reproduced in [LICENSE](LICENSE). Original authorship is retained in
`extension.toml`. Modifications made in this fork are tracked in the Git history
and summarised per release in the changelog.

## Relationship to the upstream C# extension

C# Plus is a **superset** of the upstream extension, not a companion to it. It
registers the same file suffixes (`.cs`, `.csproj`, `.slnx`, MSBuild files), so
installing both will produce duplicate language ownership. Install one or the
other:

1. Uninstall the **C#** extension from Zed's extension list.
2. Install **C# Plus**.

Your existing `lsp.omnisharp` / `lsp.roslyn` / `lsp.csharp-ls` settings continue
to work unchanged.

## Development

To develop this extension, see the [Developing Extensions](https://zed.dev/docs/extensions/developing-extensions) section of the Zed docs.
To develop this extension, see the [Developing Extensions](https://zed.dev/docs/extensions/developing-extensions)
section of the Zed docs.

### Staying current with upstream

This fork tracks two remotes: `origin` is
[joeizang/zed-csharp-plus](https://github.com/joeizang/zed-csharp-plus),
`upstream` is [zed-extensions/csharp](https://github.com/zed-extensions/csharp).

```sh
git fetch upstream && git merge upstream/main
```

See `BACKLOG.md`, item D0.1, for the upstream-sync policy.
13 changes: 13 additions & 0 deletions corpus/razor/pathological/at-in-css.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@page "/email-css"

<style>
.header {
background: @@eee;
}
@media print {
.header { background: none; }
}
</style>

<p>Styled page.</p>
8 changes: 8 additions & 0 deletions corpus/razor/pathological/at-in-text.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@page "/social"

<p>Meeting at 5@@3.</p>
<p>Email bob@@example.com and alice@@example.org today.</p>
<p>Handle: @@developer</p>
<p>Almost email: bob@@</p>
<p>Stray at: @@</p>
<p>Normal text after the stray at-sign.</p>
7 changes: 7 additions & 0 deletions corpus/razor/pathological/broken-attribute.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@page "/quote-trouble"

<img src="~/img/@Model.Name.png" alt="Logo" />
<a href="@@">Escaped in attribute</a>
<a href="@Model.Unterminated title>Broken quote</a>
<p>Text after broken attribute quoting.</p>
14 changes: 14 additions & 0 deletions corpus/razor/pathological/cascading-unterminated.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@page "/mixed-collapse"

<div>
@if (Model.Ready)
{
<ul>
@foreach (var item in Model.Items)
{
<li>@item
</ul>
</div>
<span>after the collapse</span>
@{
<p>paragraph in open block</p>
12 changes: 12 additions & 0 deletions corpus/razor/pathological/dangling-expressions.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@page "/open-expression"

<p>The value is @(Model.Value and the sentence keeps going.</p>
<p>@Model.Unterminated</p>
<p>Text after the dangling expressions.</p>

@{
var a = 1;
<p>Paragraph inside an open code block.</p>
}

<p>Final paragraph.</p>
12 changes: 12 additions & 0 deletions corpus/razor/pathological/half-typed-component-tag.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@page "/new-component"

<h1>Create</h1>

<NewComponent
<NestedPicker @bind-Value="Model.Value">
<span>inner</span>
</NestedPicker>

<ValidAfter />

<p>Content after the half-typed tags.</p>
18 changes: 18 additions & 0 deletions corpus/razor/pathological/mismatched-tags.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@page "/grid"

<div class="grid">
<table>
<thead>
<tr><th>Col</th></tr>
</tbody>
</table>
</div>

@foreach (var row in Model.Rows)
{
<tr>
<td>@row.First</td>
</tr>
}

<p>Recovered paragraph after mismatched tags.</p>
10 changes: 10 additions & 0 deletions corpus/razor/pathological/odd-directives.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@page "/odd-directives"

@whatever
@123
@@

<p>@Model.Title</p>
@Tag value in text

<p>Final line after odd directives.</p>
8 changes: 8 additions & 0 deletions corpus/razor/pathological/unterminated-comment.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@page "/comment-tangle"

@* Comment that never terminates
<div>
<p>Inside the unterminated comment</p>
</div>
<p>Paragraph after the unterminated comment.</p>
10 changes: 10 additions & 0 deletions corpus/razor/pathological/unterminated-if-block.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@page "/broken"

<div>
@if (Model.Open)
{
<p>Started but the closing brace never arrives

<span>Nested content after the broken block</span>
</div>
<p>This paragraph follows the unterminated block and must parse as an element.</p>
6 changes: 6 additions & 0 deletions corpus/razor/well-formed/at-escapes-and-email.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@page "/pricing"

<p>Contact us at support@example.com or sales@example.com.</p>
<p>The @@ escape renders a literal at-sign: user@@example.com</p>
<p>Prices start at @@5 per seat, up to @@25 for enterprise.</p>
<p>Social handles: @@zed_admin and @@dotnet.</p>
28 changes: 28 additions & 0 deletions corpus/razor/well-formed/bind-and-events.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@page "/settings"
@using System.ComponentModel.DataAnnotations

<h1>Settings</h1>

<input @bind="Enabled" />
<input @bind="Model.Quantity" @bind:after="SaveQuantity" />
<input type="checkbox" @bind="Model.Accepted" />
<select @bind="Region">
<option value="eu">Europe</option>
<option value="us">United States</option>
</select>

<button @onclick="() => Toggle(Enabled)">Toggle</button>
<button @onclick="@(e => Save(e))">Save</button>

@code {
private bool Enabled { get; set; }
private string Region { get; set; } = "eu";

private void Toggle(bool value)
{
Enabled = !value;
}

private Task Save(System.EventArgs e) => Task.CompletedTask;
private Task SaveQuantity() => Task.CompletedTask;
}
24 changes: 24 additions & 0 deletions corpus/razor/well-formed/code-block.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@page "/counter"
@using System.ComponentModel.DataAnnotations
@inject CounterState State

<h3>Counter</h3>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
private int currentCount = 0;

[Parameter]
public int StartFrom { get; set; }

protected override void OnInitialized()
{
currentCount = StartFrom;
}

private void IncrementCount()
{
currentCount += State.Step;
}
}
15 changes: 15 additions & 0 deletions corpus/razor/well-formed/component-parameters.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@page "/orders"

<OrderCard Order="@Model.CurrentOrder" Highlight="true" />
<OrderCard Order="@Model.PreviousOrder">
<CardHeader>Previous order</CardHeader>
</OrderCard>

@code {
private Dictionary<string, object> extra = new()
{
["data-testid"] = "order-card"
};
}

<OrderCard Order="@Model.DraftOrder" Extra="@extra" />
Loading