Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit 1c94757

Browse files
authored
Merge pull request #14 from pyreon/docs/add-code
docs: add code editor documentation
2 parents 84ff635 + 057e974 commit 1c94757

1 file changed

Lines changed: 322 additions & 0 deletions

File tree

content/docs/code/index.mdx

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
---
2+
title: Code Editor
3+
description: Reactive code editor for Pyreon — CodeMirror 6 with signals, minimap, diff editor, tabs, lazy-loaded languages
4+
---
5+
6+
# @pyreon/code
7+
8+
Reactive code editor built on CodeMirror 6. Signal-backed state, lazy-loaded languages, custom minimap, diff editor, tabbed multi-file editing. ~250KB modular instead of Monaco's ~2.5MB.
9+
10+
## Installation
11+
12+
```bash
13+
bun add @pyreon/code
14+
```
15+
16+
Peer dependencies: `@pyreon/core`, `@pyreon/reactivity`
17+
18+
## Quick Start
19+
20+
```tsx
21+
import { createEditor, CodeEditor } from '@pyreon/code'
22+
23+
const editor = createEditor({
24+
value: 'const greeting = "Hello, Pyreon!"',
25+
language: 'typescript',
26+
theme: 'dark',
27+
})
28+
29+
<CodeEditor instance={editor} style="height: 400px" />
30+
```
31+
32+
## Signal-Backed State
33+
34+
Every piece of editor state is a reactive signal:
35+
36+
```tsx
37+
// Read reactively
38+
editor.value() // current content
39+
editor.language() // current language
40+
editor.theme() // current theme
41+
editor.readOnly() // read-only state
42+
editor.cursor() // { line: number, col: number }
43+
editor.selection() // { from: number, to: number, text: string }
44+
editor.lineCount() // number of lines
45+
editor.focused() // has focus
46+
47+
// Write — editor updates automatically
48+
editor.value.set('new content')
49+
editor.language.set('python')
50+
editor.theme.set('dark')
51+
editor.readOnly.set(true)
52+
```
53+
54+
## Configuration
55+
56+
```tsx
57+
const editor = createEditor({
58+
value: '', // initial content
59+
language: 'typescript', // syntax highlighting language
60+
theme: 'dark', // 'light' | 'dark' | custom Extension
61+
lineNumbers: true, // show line numbers
62+
readOnly: false, // read-only mode
63+
foldGutter: true, // code folding
64+
bracketMatching: true, // bracket matching + auto-close
65+
autocomplete: true, // code completion
66+
search: true, // find & replace (Cmd+F)
67+
tabSize: 2, // tab width
68+
lineWrapping: false, // wrap long lines
69+
highlightIndentGuides: true, // indent guide lines
70+
placeholder: 'Type here...', // placeholder when empty
71+
minimap: true, // code overview sidebar
72+
vim: false, // vim keybinding mode
73+
emacs: false, // emacs keybinding mode
74+
extensions: [], // additional CodeMirror extensions
75+
onChange: (value) => {}, // called on content change
76+
})
77+
```
78+
79+
## Languages
80+
81+
20+ languages, lazy-loaded on demand — zero cost until used:
82+
83+
```tsx
84+
editor.language.set('typescript') // switch language dynamically
85+
```
86+
87+
Supported: `javascript`, `typescript`, `jsx`, `tsx`, `html`, `css`, `json`, `markdown`, `python`, `rust`, `sql`, `xml`, `yaml`, `cpp`, `java`, `go`, `php`, `ruby`, `shell`, `plain`
88+
89+
```tsx
90+
import { getAvailableLanguages, loadLanguage } from '@pyreon/code'
91+
92+
getAvailableLanguages() // list all supported
93+
await loadLanguage('typescript') // preload a language
94+
```
95+
96+
## Themes
97+
98+
```tsx
99+
import { lightTheme, darkTheme, resolveTheme } from '@pyreon/code'
100+
101+
// Switch dynamically
102+
editor.theme.set('dark')
103+
editor.theme.set('light')
104+
105+
// Custom theme — pass any CodeMirror theme Extension
106+
editor.theme.set(myCustomTheme)
107+
```
108+
109+
## Actions
110+
111+
```tsx
112+
editor.focus() // focus the editor
113+
editor.insert('// comment') // insert at cursor
114+
editor.replaceSelection('replacement') // replace selected text
115+
editor.select(0, 10) // select range
116+
editor.selectAll() // select all
117+
editor.goToLine(42) // jump to line
118+
editor.undo() // undo
119+
editor.redo() // redo
120+
editor.foldAll() // fold all code blocks
121+
editor.unfoldAll() // unfold all
122+
editor.scrollTo(position) // scroll to character position
123+
```
124+
125+
## Diagnostics (Lint Integration)
126+
127+
Push diagnostics from external tools (TypeScript, ESLint, etc.):
128+
129+
```tsx
130+
editor.setDiagnostics([
131+
{ from: 0, to: 5, severity: 'error', message: 'Unexpected token', source: 'typescript' },
132+
{ from: 20, to: 30, severity: 'warning', message: 'Unused variable', source: 'eslint' },
133+
])
134+
135+
editor.clearDiagnostics()
136+
```
137+
138+
Severities: `'error'` | `'warning'` | `'info'` | `'hint'`
139+
140+
## Line Highlights
141+
142+
Highlight specific lines (errors, breakpoints, current execution):
143+
144+
```tsx
145+
editor.highlightLine(5, 'error-line') // add highlight
146+
editor.highlightLine(10, 'current-line') // different style
147+
editor.clearLineHighlights() // remove all
148+
```
149+
150+
## Gutter Markers
151+
152+
Add icons in the gutter (breakpoints, error indicators):
153+
154+
```tsx
155+
editor.setGutterMarker(5, { text: '🔴', title: 'Breakpoint' })
156+
editor.setGutterMarker(12, { text: '⚠️', title: 'Warning', class: 'warning-marker' })
157+
editor.clearGutterMarkers()
158+
```
159+
160+
## Custom Keybindings
161+
162+
```tsx
163+
editor.addKeybinding('Ctrl-Shift-L', () => {
164+
console.log('Custom shortcut!')
165+
return true
166+
})
167+
```
168+
169+
## Text Queries
170+
171+
```tsx
172+
editor.getLine(5) // text of line 5
173+
editor.getWordAtCursor() // word under cursor
174+
```
175+
176+
## Minimap
177+
178+
Canvas-based code overview with viewport indicator and click-to-scroll:
179+
180+
```tsx
181+
const editor = createEditor({
182+
value: longCode,
183+
minimap: true, // enable minimap
184+
})
185+
```
186+
187+
The minimap renders a scaled-down view of the entire document on the right side. Click to jump to that section. The viewport rectangle shows your current position.
188+
189+
## Diff Editor
190+
191+
Side-by-side or inline diff using `@codemirror/merge`:
192+
193+
```tsx
194+
import { DiffEditor } from '@pyreon/code'
195+
196+
<DiffEditor
197+
original="const x = 1\nconst y = 2"
198+
modified="const x = 1\nconst y = 3\nconst z = 4"
199+
language="typescript"
200+
theme="dark"
201+
style="height: 400px"
202+
/>
203+
204+
// Inline diff
205+
<DiffEditor original={old} modified={new} inline />
206+
207+
// Reactive — pass signals
208+
<DiffEditor original={originalSignal} modified={modifiedSignal} />
209+
```
210+
211+
## Tabbed Editor
212+
213+
Multi-file editing with tab management:
214+
215+
```tsx
216+
import { createTabbedEditor, TabbedEditor } from '@pyreon/code'
217+
218+
const editor = createTabbedEditor({
219+
tabs: [
220+
{ name: 'index.ts', language: 'typescript', value: 'const x = 1' },
221+
{ name: 'style.css', language: 'css', value: '.app { color: red; }' },
222+
{ name: 'data.json', language: 'json', value: '{ "key": "value" }' },
223+
],
224+
theme: 'dark',
225+
})
226+
227+
<TabbedEditor instance={editor} style="height: 500px" />
228+
```
229+
230+
### Tab Operations
231+
232+
```tsx
233+
editor.tabs() // Signal<Tab[]> — all open tabs
234+
editor.activeTab() // Computed<Tab | null> — current tab
235+
editor.activeTabId() // Signal<string>
236+
237+
// Lifecycle
238+
editor.openTab({ name: 'utils.ts', language: 'typescript', value: '' })
239+
editor.closeTab('style.css')
240+
editor.switchTab('index.ts')
241+
242+
// Management
243+
editor.renameTab('index.ts', 'main.ts')
244+
editor.setModified('index.ts', true) // show modified indicator
245+
editor.moveTab(0, 2) // reorder
246+
editor.closeAll() // close all closable tabs
247+
editor.closeOthers('index.ts') // close all except one
248+
editor.getTab('index.ts') // get tab by id
249+
```
250+
251+
### Tab Features
252+
253+
- **Modified indicator** — dot shown on tabs with unsaved changes
254+
- **Closable tabs** — set `closable: false` for pinned tabs
255+
- **Content preservation** — content cached when switching tabs
256+
- **Auto-switch** — closing active tab switches to adjacent
257+
258+
## Vim / Emacs Mode
259+
260+
Optional key modes (requires installing the package):
261+
262+
```bash
263+
bun add @replit/codemirror-vim # for vim mode
264+
bun add @replit/codemirror-emacs # for emacs mode
265+
```
266+
267+
```tsx
268+
const editor = createEditor({
269+
value: 'hello world',
270+
vim: true, // enable vim mode
271+
})
272+
```
273+
274+
## Accessing CodeMirror Directly
275+
276+
For advanced use cases, access the underlying EditorView:
277+
278+
```tsx
279+
const view = editor.view() // EditorView | null (null before mount)
280+
281+
if (view) {
282+
// Use any CodeMirror API directly
283+
view.dispatch({ ... })
284+
}
285+
```
286+
287+
## API Reference
288+
289+
### createEditor
290+
291+
| Property | Type | Description |
292+
|---|---|---|
293+
| `value` | `Signal<string>` | Editor content — reactive |
294+
| `language` | `Signal<EditorLanguage>` | Current language |
295+
| `theme` | `Signal<EditorTheme>` | Current theme |
296+
| `readOnly` | `Signal<boolean>` | Read-only state |
297+
| `cursor` | `Computed<{line, col}>` | Cursor position |
298+
| `selection` | `Computed<{from, to, text}>` | Current selection |
299+
| `lineCount` | `Computed<number>` | Number of lines |
300+
| `focused` | `Signal<boolean>` | Focus state |
301+
| `view` | `Signal<EditorView \| null>` | CodeMirror instance |
302+
303+
### createTabbedEditor
304+
305+
| Method | Description |
306+
|---|---|
307+
| `openTab(tab)` | Open or switch to a tab |
308+
| `closeTab(id)` | Close a tab |
309+
| `switchTab(id)` | Switch to a tab |
310+
| `renameTab(id, name)` | Rename a tab |
311+
| `setModified(id, bool)` | Mark modified |
312+
| `moveTab(from, to)` | Reorder tabs |
313+
| `closeAll()` | Close all closable tabs |
314+
| `closeOthers(id)` | Close all except one |
315+
316+
### Components
317+
318+
| Component | Description |
319+
|---|---|
320+
| `<CodeEditor>` | Single-file editor |
321+
| `<DiffEditor>` | Side-by-side or inline diff |
322+
| `<TabbedEditor>` | Multi-file with tab bar |

0 commit comments

Comments
 (0)