Files
storybook/storybook-editor/src/highlighter.rs
Sienna Meridian Satterwhite 16deb5d237 release: Storybook v0.2.0 - Major syntax and features update
BREAKING CHANGES:
- Relationship syntax now requires blocks for all participants
- Removed self/other perspective blocks from relationships
- Replaced 'guard' keyword with 'if' for behavior tree decorators

Language Features:
- Add tree-sitter grammar with improved if/condition disambiguation
- Add comprehensive tutorial and reference documentation
- Add SBIR v0.2.0 binary format specification
- Add resource linking system for behaviors and schedules
- Add year-long schedule patterns (day, season, recurrence)
- Add behavior tree enhancements (named nodes, decorators)

Documentation:
- Complete tutorial series (9 chapters) with baker family examples
- Complete reference documentation for all language features
- SBIR v0.2.0 specification with binary format details
- Added locations and institutions documentation

Examples:
- Convert all examples to baker family scenario
- Add comprehensive working examples

Tooling:
- Zed extension with LSP integration
- Tree-sitter grammar for syntax highlighting
- Build scripts and development tools

Version Updates:
- Main package: 0.1.0 → 0.2.0
- Tree-sitter grammar: 0.1.0 → 0.2.0
- Zed extension: 0.1.0 → 0.2.0
- Storybook editor: 0.1.0 → 0.2.0
2026-02-13 21:52:03 +00:00

124 lines
3.8 KiB
Rust

//! Syntax highlighter for Storybook DSL
//!
//! Implements iced's Highlighter trait to provide line-by-line syntax
//! highlighting.
use std::ops::Range;
use iced::{
Color,
advanced::text::highlighter,
};
use crate::syntax_highlight::{
token_to_color_contextual,
tokenize,
};
/// Settings for the Storybook highlighter
#[derive(Debug, Clone, PartialEq)]
pub struct Settings;
/// Storybook syntax highlighter
#[derive(Debug)]
pub struct StorybookHighlighter {
current_line: usize,
in_prose_block: bool, // Track if we're inside a prose block
}
impl iced::widget::text::Highlighter for StorybookHighlighter {
type Highlight = Color;
type Iterator<'a> = std::vec::IntoIter<(Range<usize>, Self::Highlight)>;
type Settings = Settings;
fn new(_settings: &Self::Settings) -> Self {
Self {
current_line: 0,
in_prose_block: false,
}
}
fn update(&mut self, _new_settings: &Self::Settings) {
// No settings to update
}
fn change_line(&mut self, line: usize) {
self.current_line = line;
// Reset prose block state when jumping to a different line
self.in_prose_block = false;
}
fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_> {
let mut highlights = Vec::new();
// Check if this line starts or ends a prose block
let trimmed = line.trim_start();
if trimmed.starts_with("---") {
// This is a prose marker line
if self.in_prose_block {
// Ending a prose block
self.in_prose_block = false;
} else {
// Starting a prose block
self.in_prose_block = true;
}
// Color the entire line as a prose marker (gray)
if !line.is_empty() {
highlights.push((0..line.len(), Color::from_rgb8(0x6d, 0x6d, 0x6d)));
}
} else if self.in_prose_block {
// Inside a prose block - render as plain text in peach color
if !line.is_empty() {
highlights.push((0..line.len(), Color::from_rgb8(0xff, 0xb8, 0x6c)));
}
} else {
// Regular code - tokenize and highlight
let tokens = tokenize(line);
// Track if we're after a colon for context-aware coloring
let mut after_colon = false;
for (token, range) in tokens {
let color = token_to_color_contextual(&token, after_colon);
highlights.push((range, color));
// Update context: set after_colon when we see a colon,
// reset it when we see an identifier (field value) or certain other tokens
use storybook::syntax::lexer::Token;
match &token {
| Token::Colon => after_colon = true,
| Token::Ident(_) |
Token::IntLit(_) |
Token::FloatLit(_) |
Token::StringLit(_) |
Token::True |
Token::False |
Token::TimeLit(_) |
Token::DurationLit(_) => {
// Reset after consuming a value
after_colon = false;
},
// Don't reset for whitespace, commas, or other punctuation
| _ => {},
}
}
}
self.current_line += 1;
highlights.into_iter()
}
fn current_line(&self) -> usize {
self.current_line
}
}
/// Convert a highlight (Color) to a Format for rendering
pub fn to_format(color: &Color, _theme: &iced::Theme) -> highlighter::Format<iced::Font> {
highlighter::Format {
color: Some(*color),
font: None,
}
}