import 'package:flutter/material.dart'; import 'package:flutter_code_editor/flutter_code_editor.dart'; import 'code_editor_language.dart'; export 'code_editor_language.dart'; /// A generic code editor widget with syntax highlighting. /// /// Supports multiple languages via [CodeEditorLanguage] configuration. class CodeEditor extends StatefulWidget { const CodeEditor({ super.key, required this.language, this.initialValue = '', this.onChanged, this.readOnly = false, this.showLineNumbers = true, }); /// The programming language for syntax highlighting. final CodeEditorLanguage language; /// Initial content of the editor. final String initialValue; /// Called when the content changes. final ValueChanged? onChanged; /// Whether the editor is read-only. final bool readOnly; /// Whether to show line numbers. final bool showLineNumbers; @override State createState() => CodeEditorState(); } class CodeEditorState extends State { late CodeController _controller; @override void initState() { super.initState(); _initController(); } void _initController() { _controller = CodeController( text: widget.initialValue, language: widget.language.mode, ); _controller.addListener(_onTextChanged); } void _onTextChanged() { widget.onChanged?.call(_controller.text); } @override void didUpdateWidget(CodeEditor oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.language != widget.language) { // Language changed, recreate controller _controller.removeListener(_onTextChanged); final currentText = _controller.text; _controller.dispose(); _controller = CodeController( text: currentText, language: widget.language.mode, ); _controller.addListener(_onTextChanged); } } @override void dispose() { _controller.removeListener(_onTextChanged); _controller.dispose(); super.dispose(); } /// Gets the current text content. String get text => _controller.text; /// Sets the text content programmatically. set text(String value) { _controller.text = value; } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; return CodeTheme( data: isDark ? _darkTheme(colorScheme) : _lightTheme(colorScheme), child: SingleChildScrollView( child: CodeField( controller: _controller, readOnly: widget.readOnly, minLines: 1, gutterStyle: widget.showLineNumbers ? GutterStyle( showLineNumbers: true, showErrors: false, showFoldingHandles: false, margin: 0, textStyle: TextStyle( fontFamily: 'monospace', fontSize: 12, color: colorScheme.outline, ), background: colorScheme.surfaceContainerLow, ) : GutterStyle.none, textStyle: TextStyle( fontFamily: 'monospace', fontSize: 13, height: 1.5, color: colorScheme.onSurface, ), padding: const EdgeInsets.all(16), background: colorScheme.surfaceContainerLowest, ), ), ); } CodeThemeData _lightTheme(ColorScheme colorScheme) { return CodeThemeData( styles: { 'root': TextStyle( color: colorScheme.onSurface, backgroundColor: colorScheme.surfaceContainerLowest, ), 'keyword': TextStyle(color: Colors.purple.shade700), 'string': TextStyle(color: Colors.green.shade700), 'number': TextStyle(color: Colors.blue.shade700), 'comment': TextStyle( color: Colors.grey.shade600, fontStyle: FontStyle.italic, ), 'attr': TextStyle(color: Colors.orange.shade800), 'literal': TextStyle(color: Colors.teal.shade700), 'built_in': TextStyle(color: Colors.indigo.shade600), 'type': TextStyle(color: Colors.cyan.shade800), 'variable': TextStyle(color: Colors.brown.shade600), 'symbol': TextStyle(color: Colors.red.shade700), 'section': TextStyle(color: Colors.deepPurple.shade700), 'meta': TextStyle(color: Colors.pink.shade700), }, ); } CodeThemeData _darkTheme(ColorScheme colorScheme) { return CodeThemeData( styles: { 'root': TextStyle( color: colorScheme.onSurface, backgroundColor: colorScheme.surfaceContainerLowest, ), 'keyword': const TextStyle(color: Color(0xFFC792EA)), 'string': const TextStyle(color: Color(0xFFC3E88D)), 'number': const TextStyle(color: Color(0xFFF78C6C)), 'comment': TextStyle( color: Colors.grey.shade500, fontStyle: FontStyle.italic, ), 'attr': const TextStyle(color: Color(0xFFFFCB6B)), 'literal': const TextStyle(color: Color(0xFF82AAFF)), 'built_in': const TextStyle(color: Color(0xFF89DDFF)), 'type': const TextStyle(color: Color(0xFFFFCB6B)), 'variable': const TextStyle(color: Color(0xFFEEFFFF)), 'symbol': const TextStyle(color: Color(0xFFF07178)), 'section': const TextStyle(color: Color(0xFF82AAFF)), 'meta': const TextStyle(color: Color(0xFFF78C6C)), }, ); } }