Skip to content

Commit 7a3d247

Browse files
fix(e2e): increase performance thresholds for CI runners + Athame spec (#9)
* fix(e2e): increase performance thresholds for CI runners CI runners (especially Windows/webkit) are slower than local machines. Adjusted thresholds to be CI-friendly while still meaningful: - interactionResponse: 150ms → 250ms - typingLatency: 50ms → 75ms - tabSwitch: 200ms → 350ms - eventDispatch: 50ms → 100ms - keyboard events: 1000ms → 1500ms for 20 events 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add specs directory - ATHAME-SPEC.md: Athame specification - README.md: Specs index 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Lilith Crook <paraphilic-ecchymosis@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e61a0d7 commit 7a3d247

2 files changed

Lines changed: 416 additions & 0 deletions

File tree

docs/specs/ATHAME-SPEC.md

Lines changed: 388 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,388 @@
1+
# Athame - Sigil Code Editor Specification
2+
3+
> *"A ritual blade for inscribing sigils"*
4+
5+
**Version:** 1.0.0
6+
**Date:** 2026-01-31
7+
**Status:** Draft (extracted from implementation)
8+
**Component:** `qliphoth/components/athame/`
9+
10+
---
11+
12+
## 1. Overview
13+
14+
Athame is a code editor component for Sigil, designed for embedding in web applications (via Qliphoth) and the sigil-lang.com playground. It provides syntax highlighting, basic editing operations, and undo/redo history.
15+
16+
### 1.1 Design Goals
17+
18+
1. **Native Sigil Implementation** — Written in Sigil, compiles to WASM
19+
2. **Syntax-Aware** — Tokenizer understands Sigil's unique syntax (morphemes, evidentiality, native symbols)
20+
3. **Embeddable** — Works as a Qliphoth component or standalone
21+
4. **Lightweight** — Minimal dependencies, fast load times
22+
23+
### 1.2 Architecture
24+
25+
```
26+
athame/
27+
├── src/
28+
│ ├── mod.sigil # Module exports
29+
│ ├── tokenizer.sigil # Lexer for syntax highlighting
30+
│ ├── state.sigil # Editor state management
31+
│ ├── history.sigil # Undo/redo stack
32+
│ ├── viewport.sigil # Visible line range calculation
33+
│ ├── highlight.sigil # Syntax highlighting spans
34+
│ ├── editor.sigil # Core editor logic
35+
│ ├── component.sigil # Qliphoth component wrapper
36+
│ └── playground.sigil # Playground-specific integration
37+
└── tests/
38+
├── tokenizer_test.sigil
39+
├── state_test.sigil
40+
├── history_test.sigil
41+
└── rendering_test.sigil
42+
```
43+
44+
---
45+
46+
## 2. Tokenizer Specification
47+
48+
The tokenizer lexes Sigil source code into tokens for syntax highlighting.
49+
50+
### 2.1 Token Types
51+
52+
```sigil
53+
enum TokenKind {
54+
Keyword, // Language keywords
55+
Identifier, // Variable/function names
56+
Type, // Type names (capitalized identifiers)
57+
String, // String literals
58+
Number, // Numeric literals
59+
Comment, // Line and block comments
60+
Operator, // Arithmetic, comparison, logical operators
61+
Morpheme, // Greek letter pipeline operators
62+
NativeSymbol, // Sigil-specific symbols (≔, ⎇, ⟳, etc.)
63+
EvidenceKnown, // ! marker after identifier
64+
EvidenceUncertain, // ? marker after identifier
65+
EvidenceReported, // ~ marker after identifier
66+
EvidenceParadox, // ‽ interrobang
67+
Punctuation, // Brackets, commas, semicolons
68+
Whitespace, // Spaces, tabs
69+
Newline, // Line breaks
70+
Unknown, // Unrecognized characters
71+
}
72+
```
73+
74+
### 2.2 Keywords
75+
76+
The tokenizer recognizes both legacy (Rust-compatible) and native Sigil keywords:
77+
78+
**Legacy Keywords (aliases):**
79+
```
80+
fn, let, mut, if, else, match, return, for, while, in,
81+
struct, enum, trait, impl, use, pub, async, await,
82+
true, false, self, Self, super, loop, break, continue,
83+
const, where
84+
```
85+
86+
**Native Sigil Keywords:**
87+
```
88+
rite, sigil, aspect, vary, yea, nay, each, of,
89+
forever, this, This, above, invoke, scroll, tome
90+
```
91+
92+
### 2.3 Morpheme Characters
93+
94+
Greek letters used as semantic pipeline operators:
95+
96+
| Character | Unicode | Name | Operation |
97+
|-----------|---------|------|-----------|
98+
| τ | U+03C4 | tau | Transform (map) |
99+
| φ | U+03C6 | phi | Filter |
100+
| σ | U+03C3 | sigma | Sort |
101+
| ρ | U+03C1 | rho | Reduce |
102+
| Σ | U+03A3 | Sigma | Sum |
103+
| Π | U+03A0 | Pi | Product |
104+
| α | U+03B1 | alpha | First |
105+
| ω | U+03C9 | omega | Last |
106+
| μ | U+03BC | mu | Merge |
107+
| λ | U+03BB | lambda | Lambda/function |
108+
109+
**Uppercase variants also recognized:** Τ, Φ, Ρ, Α, Ω, Μ, Λ, Θ
110+
111+
### 2.4 Native Symbols
112+
113+
Sigil-specific Unicode symbols for control flow and structure:
114+
115+
| Symbol | Unicode | Meaning |
116+
|--------|---------|---------|
117+
|| U+2254 | Assignment (let) |
118+
| Δ | U+0394 | Mutable modifier |
119+
|| U+2387 | If |
120+
|| U+2389 | Else |
121+
|| U+2325 | Match |
122+
|| U+27F3 | While loop |
123+
|| U+221E | Forever loop |
124+
|| U+2200 | For all |
125+
|| U+2208 | In (membership) |
126+
|| U+2227 | Logical AND |
127+
|| U+2228 | Logical OR |
128+
| ¬ | U+00AC | Logical NOT |
129+
|| U+2609 | Public export |
130+
|| U+16C8 | Enum declaration |
131+
| · | U+00B7 | Module separator |
132+
|| U+2192 | Return type arrow |
133+
134+
### 2.5 Evidentiality Markers
135+
136+
Context-sensitive tokenization for evidentiality:
137+
138+
- `!` after identifier/type → `EvidenceKnown`
139+
- `?` after identifier/type → `EvidenceUncertain`
140+
- `~` after identifier/type → `EvidenceReported`
141+
- `` (U+203D) anywhere → `EvidenceParadox`
142+
- `!`, `?`, `~` in other contexts → `Operator`
143+
144+
### 2.6 Comments
145+
146+
- **Line comments:** `// ...` until newline
147+
- **Block comments:** `/* ... */` with nesting support
148+
149+
### 2.7 Two-Character Operators
150+
151+
```
152+
==, !=, <=, >=, &&, ||, ->, =>,
153+
+=, -=, *=, /=, ::
154+
```
155+
156+
---
157+
158+
## 3. Editor State
159+
160+
### 3.1 State Structure
161+
162+
```sigil
163+
sigil EditorState {
164+
content: String, // Full document text
165+
cursor_pos: i64, // Cursor position (character offset)
166+
selection: OptionSelection, // Optional selection range
167+
scroll_top: i64, // Scroll position (pixels)
168+
line_height: i64, // Line height for calculations
169+
viewport_height: i64, // Visible area height
170+
}
171+
```
172+
173+
### 3.2 Selection
174+
175+
```sigil
176+
sigil Selection {
177+
start: i64, // Selection start offset
178+
end: i64, // Selection end offset
179+
}
180+
```
181+
182+
### 3.3 Signals
183+
184+
Reactive state updates via signals:
185+
186+
```sigil
187+
sigil Signal<T> {
188+
value: T,
189+
subscribers: Vec<fn(T)>,
190+
}
191+
```
192+
193+
---
194+
195+
## 4. History (Undo/Redo)
196+
197+
### 4.1 History Entry
198+
199+
```sigil
200+
sigil HistoryEntry {
201+
content: String, // Document state
202+
cursor_pos: i64, // Cursor position at this state
203+
timestamp: i64, // When this entry was created
204+
}
205+
```
206+
207+
### 4.2 History Stack
208+
209+
```sigil
210+
sigil HistoryStack {
211+
entries: Vec<HistoryEntry>,
212+
current_index: i64,
213+
max_entries: i64, // Default: 100
214+
}
215+
```
216+
217+
### 4.3 Operations
218+
219+
| Operation | Behavior |
220+
|-----------|----------|
221+
| `push(entry)` | Add new entry, truncate redo stack |
222+
| `undo()` | Move to previous entry if available |
223+
| `redo()` | Move to next entry if available |
224+
| `can_undo()` | Returns true if undo available |
225+
| `can_redo()` | Returns true if redo available |
226+
227+
---
228+
229+
## 5. Editor API
230+
231+
### 5.1 Constructor
232+
233+
```sigil
234+
athame_new() → Athame
235+
athame_with_content(content: String) → Athame
236+
```
237+
238+
### 5.2 Content Operations
239+
240+
```sigil
241+
athame_get_content(editor: &Athame) → String
242+
athame_set_content(editor: &mut Athame, content: String)
243+
athame_insert(editor: &mut Athame, text: String)
244+
athame_delete_backward(editor: &mut Athame)
245+
athame_delete_forward(editor: &mut Athame)
246+
athame_newline(editor: &mut Athame)
247+
athame_tab(editor: &mut Athame) // Inserts 4 spaces
248+
```
249+
250+
### 5.3 Cursor Movement
251+
252+
```sigil
253+
athame_move_left(editor: &mut Athame)
254+
athame_move_right(editor: &mut Athame)
255+
athame_move_home(editor: &mut Athame) // Start of line
256+
athame_move_end(editor: &mut Athame) // End of line
257+
```
258+
259+
### 5.4 History
260+
261+
```sigil
262+
athame_undo(editor: &mut Athame) → bool
263+
athame_redo(editor: &mut Athame) → bool
264+
athame_can_undo(editor: &Athame) → bool
265+
athame_can_redo(editor: &Athame) → bool
266+
```
267+
268+
### 5.5 Viewport
269+
270+
```sigil
271+
athame_scroll_to(editor: &mut Athame, position: i64)
272+
athame_scroll_by(editor: &mut Athame, delta: i64)
273+
athame_ensure_cursor_visible(editor: &mut Athame)
274+
athame_get_visible_range(editor: &Athame) → LineRange
275+
athame_get_render_range(editor: &Athame) → LineRange // With overscan
276+
athame_get_cursor_line(editor: &Athame) → i64
277+
```
278+
279+
### 5.6 Syntax Features
280+
281+
```sigil
282+
athame_find_matching_bracket(editor: &Athame) → OptionBracketPair
283+
athame_get_line_highlights(editor: &Athame, line: i64) → Vec<HighlightSpan>
284+
```
285+
286+
### 5.7 Keyboard Handling
287+
288+
```sigil
289+
athame_handle_key(editor: &mut Athame, event: KeyEvent) → bool
290+
```
291+
292+
---
293+
294+
## 6. Syntax Highlighting CSS Classes
295+
296+
For rendering highlighted tokens, use these CSS class mappings:
297+
298+
| TokenKind | CSS Class |
299+
|-----------|-----------|
300+
| Keyword | `ath-keyword` |
301+
| Type | `ath-type` |
302+
| String | `ath-string` |
303+
| Number | `ath-number` |
304+
| Comment | `ath-comment` |
305+
| Operator | `ath-operator` |
306+
| Morpheme | `ath-morpheme` |
307+
| NativeSymbol | `ath-native` |
308+
| EvidenceKnown | `ath-evidence-known` |
309+
| EvidenceUncertain | `ath-evidence-uncertain` |
310+
| EvidenceReported | `ath-evidence-reported` |
311+
| EvidenceParadox | `ath-evidence-paradox` |
312+
| Identifier | (no class, default text) |
313+
| Punctuation | (no class, default text) |
314+
| Whitespace | (preserved as-is) |
315+
| Newline | (preserved as-is) |
316+
| Unknown | (no class, default text) |
317+
318+
---
319+
320+
## 7. Qliphoth Component
321+
322+
### 7.1 Component Props
323+
324+
```sigil
325+
sigil AthameProps {
326+
initial_content: String,
327+
on_change: OptionCallback, // fn(String)
328+
read_only: bool,
329+
line_numbers: bool,
330+
highlight_active_line: bool,
331+
}
332+
```
333+
334+
### 7.2 Component Usage
335+
336+
```sigil
337+
use athame::component::AthameEditor;
338+
339+
fn CodeEditor() -> Element {
340+
AthameEditor {
341+
initial_content: "// Hello, Sigil!",
342+
on_change: Some(|content| save_draft(content)),
343+
read_only: false,
344+
line_numbers: true,
345+
highlight_active_line: true,
346+
}
347+
}
348+
```
349+
350+
---
351+
352+
## 8. Testing Requirements
353+
354+
### 8.1 Tokenizer Tests
355+
356+
- All keywords tokenize as `Keyword`
357+
- Capitalized identifiers tokenize as `Type`
358+
- All morpheme characters tokenize as `Morpheme`
359+
- All native symbols tokenize as `NativeSymbol`
360+
- Evidentiality markers context-sensitive
361+
- Nested block comments handled correctly
362+
- Escape sequences in strings preserved
363+
364+
### 8.2 Editor Tests
365+
366+
- Insert/delete operations update content correctly
367+
- Cursor movement respects line boundaries
368+
- Undo/redo restores previous states
369+
- Tab inserts 4 spaces (not tab character)
370+
371+
### 8.3 Integration Tests
372+
373+
- Qliphoth component renders correctly
374+
- Keyboard events handled properly
375+
- Scroll sync between textarea and highlight layer
376+
377+
---
378+
379+
## 9. Revision History
380+
381+
| Version | Date | Author | Changes |
382+
|---------|------|--------|---------|
383+
| 1.0.0 | 2026-01-31 | Claude Opus 4.5 | Initial spec extracted from implementation |
384+
385+
---
386+
387+
*Athame: From the ceremonial blade used to direct energy in ritual magic.
388+
In Sigil, it directs the flow of code.*

0 commit comments

Comments
 (0)