A code editor control,
drawn on canvas.

Monospace, fixed character grid, canvas-rendered — a fast, extensible code editor control for Avalonia. Folding, CodeLens, column selection, pluggable gutters, context popovers, and TextMate highlighting with drop-in custom languages.

dotnet add package AvaCodeEditor

Latest version: 12.0.0 · built for Avalonia 12

Half a minute, every headline feature

Folding, CodeLens, breakpoints, column selection, a million lines and a blame column that arrives late — recorded from the demo below, nothing staged.

No narration, no cuts to a slide: every frame is the control running in a browser tab.

Built to be extended

A document open in the editor with a line-number gutter

Canvas glyph-grid rendering

Every glyph occupies exactly one cell — text↔pixel mapping is pure arithmetic. No per-character UI objects; large files stay fast.

C# highlighted by a TextMate grammar chosen from the file name

Extensible highlighting

TextMate grammars with scope-based theming. Add your own language by dropping in a .tmLanguage.json — no recompilation.

A bookmark gutter marking three lines beside the line numbers

Pluggable margins

Line numbers, change markers, git blame — gutters are host-provided components composed by the editor.

Push-change buttons anchored beside three loops

Inline action buttons

Anchor buttons to line blocks — like the ≫ / ≪ merge buttons in diff tools — rendered and hit-tested by the editor, defined by your app.

A blame column showing commit, date and author beside the code

Line annotations

Per-line metadata — who changed this line, and when — arriving asynchronously into a column of declared width, so the text never shifts sideways when a longer name scrolls into view. One label per run of like lines; the whole of it in a tooltip on every line.

Folded regions showing a placeholder, with CodeLens rows above declarations

Folding and CodeLens

Collapse a region into its first line, and put a clickable row of information above a declaration. Screen rows and document lines stop being the same thing — and the caret, the gutter and every click follow.

A rectangular selection over a column of numbers, one caret per line

Columns and many carets

Alt+drag a rectangle or Shift+Alt+arrow one open: a caret per line, edits applied at all of them as a single undo step, and copying a column gives you the column.

A popover anchored to a word, listing actions for what is under the pointer

Context popovers

Right-click and the editor tells you the position, the word, the selection and the TextMate scopes under it, then anchors whatever control you hand back to that character cell.

Coloured bands behind changed lines and highlights inside them

Bands and highlights

Paint behind whole lines — a diff's added, removed and conflicting bands — and behind runs of characters inside one, for the words that actually changed.

The same document in the app's theme and in a host's own palette

Light & dark themes

Theme files map token scopes to styles; switching themes never re-tokenizes the document. User-supplied themes welcome.

Gutters that fail safely

A margin is your code, called on every frame. One that throws costs its own column and raises MarginFailed — never the editor, and never the unsaved document in it.

Three lines to a code editor

The control is a control. Put it in a window, give it a buffer, and you have an editor with a caret, a selection, undo and a fixed character grid.

<Window xmlns:editor="using:AvaCodeEditor">
  <editor:CodeEditor x:Name="Editor" />
</Window>
Editor.Buffer = new TextBuffer(File.ReadAllText(path));
Editor.Margins.Add(new LineNumberMargin());

// Highlighting: a grammar chosen by file name, a theme chosen by appearance.
var languages = new TextMateLanguageRegistry();
Editor.SyntaxTokenizer = languages.FindByFileName(path)?.CreateTokenizer();
Editor.HighlightTheme = languages.LoadTheme(ThemeName.DarkPlus);

Everything past that is an interface you implement: the editor knows nothing about diffs, git or your domain, and never will.

Run the demo

A themed sample app ships with every release, in the same repository as the packages. Twelve scenarios, each one a small file you can read — the code below the window is the whole of what makes it work.

Editing

Caret, selection, undo, and a document you type into.

Syntax highlighting

Four languages in one editor, the grammar chosen by file name.

A margin of your own

A bookmark gutter in forty lines — reserve a width, draw, hit-test.

Actions on a block

Buttons anchored to ranges of lines that rewrite the code under them.

Annotations, arriving late

A blame column that is empty, and then is not — the async case, on purpose.

Bands and highlights

Colour behind whole lines, and behind runs of characters inside one.

Breakpoints and the current line

A debugger's editor: a red dot in the gutter, the next statement banded yellow with the arrow beside it.

Regions and CodeLens

Chevrons that fold a block into its first line, and a clickable row of references and authorship above each declaration.

Columns and many carets

Alt+drag a rectangle, get a caret per line, and type into all of them as one undo step.

A popover of your own

Right-click, and the editor hands you the word, the selection and the syntax scopes — you decide what to show.

A million lines

Opened instantly, and editable: the demo's buffer composes a line when the editor asks for it.

Themes, and overriding them

Light and dark, and a host that disagrees winning on its own resource keys.

The demo builds against the published package, not against a copy of the source — so if a release is broken, the demo says so.

Documentation

Getting started, the document model, and the extensibility interfaces.