A powerful, feature-rich code editor created using Flutter
Bring VS Code-level editing experience to your Flutter apps
A complete and better alternative for re_editor, flutter_code_crafter, flutter_code_editor, code_text_field, etc

large code support (tested with 100k+ lines) and LSP based intelligent lazy highlighting
Note
code_forge does not support Flutter web, as it relies on dart:io for core functionality. Use code_forge_web for web support.
- FEATURE: Added comprehensive RTL support for right-to-left languages (Arabic, Hebrew, etc.)
- Added
textDirectionparameter toCodeForgewidget to control text layout direction - Gutter automatically positions on the right side for RTL mode
- Text rendering properly aligned for RTL languages with full visual direction support
- Caret positioning and movement follow visual direction (not logical) for intuitive editing
- Selection highlighting works correctly for RTL text
- All UI elements (fold icons, line numbers, indentation guides) properly mirrored for RTL
- Bracket pair highlighting supports RTL
- Scroll behavior adapted for RTL layout
- Added
- FEATURE: Arrow keys follow visual direction for RTL
- Left arrow visually moves left (logically moves right in RTL)
- Right arrow visually moves right (logically moves left in RTL)
- Home key moves to visual line start (line end in RTL)
- End key moves to visual line end (line start in RTL)
- Ctrl+Arrow word navigation follows visual direction for RTL
- FEATURE: Arabic and Hebrew word detection for code completion
- Updated word pattern matching to include Arabic (U+0600-U+06FF), Extended Arabic (U+08A0-U+08FF), and Hebrew (U+0590-U+05FF) Unicode ranges
- LSP suggestions now work correctly for RTL languages
- Word cache includes RTL script characters
- Fold icons display correctly for RTL (< for folded, down arrow for unfolded)
- ENHANCEMENT: Improved hover popup positioning and visibility
- Hover documentation now positions above cursor if space is limited below
- Better width constraints and viewport-aware positioning
- Added hover content caching for improved performance
- Hover content is fetched asynchronously without blocking rendering
- Diagonal offset adjustment prevents hover from blocking cursor area
- ENHANCEMENT: Hover triggered by tap on mobile/desktop now persists properly
- Added
onHoverSetByTapcallback for better tap-based hover handling - Hover state properly managed to avoid flicker
- Added
- FIX: Auto-indentation now only triggers on single Enter key press
- Paste operations no longer re-indent pasted multi-line content incorrectly
- Only the first newline in pasted text triggers auto-indent
- FIX: CCLS semantic highlighting refresh debouncing
- Added
_scheduleCclsRefreshwith 1 second debounce to avoid excessive document saves - CCLS servers that use custom semantic token protocol now work more reliably
- Added
- ENHANCEMENT: Better suggestion popup positioning
- Popup now positions above cursor when limited space below
- Horizontal alignment adjusted to stay within viewport
- Improved mobile responsiveness
- Modified paragraph style to respect textDirection property
- Added RTL-aware cache invalidation for paragraph building
- Improved caret info calculation for RTL text positioning
- Enhanced text offset to line/char conversion for RTL
- Selection handle positioning adapted for RTL layout
- Ghost text (AI completion) positioning corrected for RTL
- Inlay hints and document colors properly positioned for RTL
CodeForge is a next-generation code editor widget designed for developers who demand more. Whether you're building an IDE, a code snippet viewer, or an educational coding platform, CodeForge delivers:
| Feature | CodeForge | Others |
|---|---|---|
| 🎨 Syntax Highlighting | ✅ 180+ languages Availabe languages |
✅ |
| 📁 Code Folding | ✅ Smart detection | |
| 🔌 LSP Integration | ✅ Full support | ❌ |
| 🤖 AI Completion | ✅ Multi-model | ❌ |
| ⚡ Semantic Tokens | ✅ Real-time | ❌ |
| 🎯 Diagnostics | ✅ Inline errors | ❌ |
| ↩️ Undo/Redo | ✅ Smart grouping | |
| 🎨 Full Theming | ✅ Everything Available themes |
- Uses the rope data structure instead of regular char array to to handle large text.
- Uses flutter's low level
RenderBoxandParagrahBuilderto render text insted ofTextFieldfor efficiency. - Built in Language Server Protocol client
- AI Code completion.
View all features with live demos: CodeForge Features Showcase
To see working examples of all CodeForge features including AI Code Completion, LSP Integration, Smart Code Folding, Syntax Highlighting, Search and Replace, and RTL Language Support, visit the features showcase page above.
📋 Complete Feature List
- ⚡ Rope Data Structure — Optimized for large files
- 🎨 180+ Languages — Via
re_highlightpackage - 📁 Code Folding — Smart block detection
- 📏 Indentation Guides — Visual code structure
- 🔢 Line Numbers — With active line highlighting
- ↩️ Smart Undo/Redo — Timestamp-based grouping
- 🔍 Search Highlighting — Find and highlight matches
- ✂️ Line Operations — Move, duplicate, delete lines
- 💡 Intelligent Completions — Context-aware code suggestions with auto-import
- 📖 Hover Documentation — Rich markdown tooltips with type information
- 🚨 Real-time Diagnostics — Errors and warnings with quick fixes
- 🎨 Semantic Highlighting — Token-based coloring with modifiers
- 💬 Signature Help — Function signatures and parameter hints
- 🔧 Code Actions — Quick fixes and refactoring suggestions
- ✨ Inlay Hints — Inline annotations for types and parameters
- 🎯 Document Highlight — Highlight symbol occurrences
- 🎨 Document Colors — Color value detection and picker
- 📍 Go to Definition — Navigate to symbol definitions
- ✏️ Symbol Renaming — Rename symbols across workspace
- 📡 Multiple Protocols — Stdio and WebSocket support
- ⚙️ Capability Control — Selectively enable/disable LSP features
- 🎨 Full Theming — Every element customizable
- 📐 Gutter Styling — Colors, icons, sizes
- ✨ Selection Styling — Cursor, selection, bubbles
- 💬 Popup Styling — Suggestions, hover details
Add CodeForge to your pubspec.yaml:
dependencies:
code_forge: ^8.0.0Then run:
flutter pub getImport a theme and a language from the re_highlight package and you are good to go. (Defaults to langDart and vs2015Theme):
import 'package:flutter/material.dart';
import 'package:code_forge/code_forge.dart';
import 'package:re_highlight/languages/python.dart';
import 'package:re_highlight/styles/atom-one-dark.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: CodeForge(
language: langPython, // Defaults to langDart
editorTheme: atomOneDarkTheme, // Defaults to vs2015Theme
),
),
);
}
}For more control over the editor:
class _EditorState extends State<Editor> {
final _controller = CodeForgeController();
final _undoController = UndoRedoController();
@override
Widget build(BuildContext context) {
return CodeForge(
controller: _controller, // Optional controller for more features.
undoController: _undoController, // Optional undo controller to control the undo-redo operations.
);
}
}Connect to any Language Server Protocol compatible server for intelligent code assistance.
CodeForge provides a built-in LSP client that allows you to connect to any LSP server for intelligent highlighting, completions, hover details, diagnostics, and more.
- Using WebSocket (easy and recommended)
- Using stdio
The class LspSocketConfig is used to connect to an LSP server using WebSocket. It takes the following parameters:
serverUrl: The WebSocket URL of the LSP server.filePath: A filePath is required by the LSP server to provide completions and diagnostics.workspacePath: The workspace path is the current directory or the parent directory which holds thefilePathfile.languageId: This is a server specific parameter. eg:'python'is the language ID used in basedpyright/pyright language server.
You can easily start any language server using websocket using the lsp-ws-proxy package. For example, to start the basedpyright language server, you can use the following command:
(On Android, you can use Termux)
cd /Downloads/lsp-ws-proxy_linux # Navigate to the directory where lsp-ws-proxy is located
./lsp-ws-proxy --listen 5656 -- basedpyright-langserver --stdio # Start the pyright language server on port 5656create a LspSocketConfig object and pass it to the CodeForgeController widget.
final lspConfig = LspSocketConfig(
workspacePath: "/home/athul/Projects/lsp",
languageId: "python",
serverUrl: "ws://localhost:5656"
),Then pass the lspConfig instance to the CodeForgeController widget:
final _controller = CodeForgeController(
lspConfig: lspConfig // Pass the LspConfig here.
)
CodeForge(
controller: _controller, // Pass the controller here.
theme: anOldHopeTheme,
filePath: "/home/athul/Projects/lsp/example.py"
),This method is easy to start—no terminal setup or extra packages are needed—but it does require a bit more setup in your code. The LspStdioConfig.start() method connects to an LSP server using stdio and is asynchronous, so you'll typically use a FutureBuilder to handle initialization. It accepts the following parameters:
executable: Location of the LSP server executable file.args: Arguments to pass to the LSP server executable.filePath: A filePath is required by the LSP server to provide completions and diagnostics.workspacePath: The workspace path is the current directory or parent directory which holds thefilePathfile.languageId: This is a server specific parameter. eg:'python'is the language ID used in pyright language server.
To get the executable path, you can use the which command in the terminal. For example, to get the path of the basedpyright-langserver, you can use the following command:
which basedpyright-langserverCreate an async method to initialize the LSP configuration.
Future<LspConfig?> _initLsp() async {
try {
final config = await LspStdioConfig.start(
executable: '/home/athul/.nvm/versions/node/v20.19.2/bin/basedpyright-langserver',
args: ['--stdio'],
workspacePath: '/home/athul/Projects/lsp',
languageId: 'python',
);
return config;
} catch (e) {
debugPrint('LSP Initialization failed: $e');
return null;
}
}Then use a FutureBuilder to initialize the LSP configuration and pass it to the CodeForgeController widget:
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: FutureBuilder(
future: _initLsp(), // Call the async method to get the LSP config.
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return CodeForge(
editorTheme: anOldHopeTheme,
controller: CodeForgeController(
lspConfig: snapshot.data // Pass the config here.
),
filePath: '/home/athul/Projects/lsp/example.py',
textStyle: TextStyle(fontSize: 15, fontFamily: 'monospace'),
);
}
),
)
),
);
}Future<LspConfig> setupDartLsp() async {
return await LspStdioConfig.start(
executable: 'dart',
args: ['language-server', '--protocol=lsp'],
workspacePath: '/path/to/your/project',
languageId: 'dart',
);
}
// In your widget
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: FutureBuilder<LspConfig>(
future: setupDartLsp(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
return CodeForge(
language: langDart,
textStyle: GoogleFonts.jetBrainsMono(),
controller: CodeForgeController(
lspConfig: snapshot.data
),
filePath: '/path/to/your/file.dart', // Mandatory field
)
},
),
),
),
);
}CodeForge offers extensive customization options for every aspect of the editor.
CodeForge(
controller: controller,
language: langDart,
// Editor theme (syntax colors)
editorTheme: vs2015Theme,
// Text styling
textStyle: GoogleFonts.jetBrainsMono(fontSize: 14),
// AI Completion styling
aiCompletionTextStyle: TextStyle(
color: Colors.grey, // Change the color of the AI completion text
fontStyle: FontStyle.italic, // Make the AI completion text italic
),
// Selection & cursor
selectionStyle: CodeSelectionStyle(
cursorColor: Colors.white,
selectionColor: Colors.blue.withOpacity(0.3),
cursorBubbleColor: Colors.blue,
),
// Gutter (line numbers & fold icons)
gutterStyle: GutterStyle(
lineNumberStyle: TextStyle(color: Colors.grey),
backgroundColor: Color(0xFF1E1E1E),
activeLineNumberColor: Colors.white,
foldedIconColor: Colors.grey,
unfoldedIconColor: Colors.grey,
errorLineNumberColor: Colors.red,
warningLineNumberColor: Colors.orange,
),
// Suggestion popup
suggestionStyle: SuggestionStyle(
backgroundColor: Color(0xFF252526),
textStyle: TextStyle(color: Colors.white),
elevation: 8,
),
// Hover documentation
hoverDetailsStyle: HoverDetailsStyle(
backgroundColor: Color(0xFF252526),
textStyle: TextStyle(color: Colors.white),
),
// Highlight matching text using [controller.findWord()] and [controller.findRegex()]
matchHighlightStyle: const MatchHighlightStyle(
currentMatchStyle: TextStyle(
backgroundColor: Color(0xFFFFA726),
),
otherMatchStyle: TextStyle(
backgroundColor: Color(0x55FFFF00),
),
),
)CodeForge(
// Enable/disable features
enableFolding: true, // Code folding
enableGutter: true, // Line numbers
enableGuideLines: true, // Indentation guides
enableGutterDivider: false, // Gutter separator line
enableSuggestions: true, // Autocomplete
enableKeyboardSuggestions: true // Suggestions from the OS keyboard
// Behavior
readOnly: false, // Read-only mode
autoFocus: true, // Auto-focus on mount
lineWrap: false, // Line wrapping
)| Property | Type | Description |
|---|---|---|
controller |
CodeForgeController? |
Text and selection controller |
findController |
FindController? |
Finder controller for managing search functionality |
undoController |
UndoRedoController? |
Undo/redo history controller |
editorTheme |
Map<String, TextStyle>? |
Syntax color theme |
language |
Mode? |
Syntax highlighting language |
focusNode |
FocusNode? |
Focus node for managing keyboard focus |
textStyle |
TextStyle? |
Base text style |
ghostTextStyle |
TextStyle? |
Text style for ghost text (inline suggestions) |
innerPadding |
EdgeInsets? |
Padding inside the editor content area |
verticalScrollController |
ScrollController? |
Custom scroll controller for vertical scrolling |
horizontalScrollController |
ScrollController? |
Custom scroll controller for horizontal scrolling |
selectionStyle |
CodeSelectionStyle? |
Selection styling |
gutterStyle |
GutterStyle? |
Gutter styling |
suggestionStyle |
SuggestionStyle? |
Suggestion popup styling |
hoverDetailsStyle |
HoverDetailsStyle? |
Hover popup styling |
matchHighlightStyle |
MatchHighlightStyle? |
Highlight the matching words in the controller.findWord() API |
filePath |
String? |
File path for LSP |
initialText |
String? |
Initial editor content |
readOnly |
bool |
Read-only mode |
lineWrap |
bool |
Line wrapping |
autoFocus |
bool |
Auto-focus on mount |
enableFolding |
bool |
Enable code folding |
enableGuideLines |
bool |
Show indentation guides |
enableGutter |
bool |
Show line numbers |
enableGutterDivider |
bool |
Show gutter divider |
enableSuggestions |
bool |
Enable autocomplete suggestions |
enableKeyboardSuggestions |
bool |
Show auto completions in OS virtual keyboard |
keyboardType |
TextInputType |
Type of virtual keyboard |
deleteFoldRangeOnDeletingFirstLine |
bool |
When true, deleting the first line of a folded block removes the entire block |
finderBuilder |
PreferredSizeWidget Function(FindController findController)? |
Builder for custom Finder widget |
final controller = CodeForgeController();
// Text operations
controller.text = 'Hello, World!';
String content = controller.text;
controller.getLineText(int lineIndex);
controller.insertText(String text, int line, int character);
controller.insertAtCurrentCursor(String text);
// Selection & modification
controller.selection = TextSelection(baseOffset: 0, extentOffset: 5);
controller.selectAll();
controller.copy();
controller.cut();
controller.paste();
// Line operations
int lineCount = controller.lineCount;
String line = controller.getLineText(0);
int lineStart = controller.getLineStartOffset(0);
controller.duplicateLine();
controller.moveLineDown();
controller.moveLineUp();
controller.backspace();
controller.delete();
// Folding
controller.foldAll();
controller.unfoldAll();
controller.toggleFold(lineNumber);
// Search & find
controller.findWord(String word, matchCase: false, matchWholeWord: false);
controller.findRegex(String pattern);
controller.searchHighlights = [
SearchHighlight(start: 0, end: 5, color: Colors.yellow),
];
// Scroll navigation
controller.scrollToLine(int line);
// Inlay hints
await controller.fetchInlayHints(int startLine, int startCharacter, int endLine, int endCharacter);
controller.showInlayHints();
controller.hideInlayHints();
controller.setInlayHints(List<InlayHint> hints);
controller.clearInlayHints();
// Document colors
await controller.fetchDocumentColors();
// Document highlights
await controller.fetchDocumentHighlights(int line, int character);
controller.clearDocumentHighlights();
// LSP features
await controller.callSignatureHelp();
controller.getCodeAction();
// Editor decorations
controller.setGitDiffDecorations(
addedRanges: [(int startLine, int endLine), ...],
removedRanges: [...],
modifiedRanges: [...],
addedColor: const Color(0xFF4CAF50),
removedColor: const Color(0xFFE53935),
modifiedColor: const Color(0xFF2196F3),
);
controller.clearGitDiffDecorations();
controller.addLineDecoration(LineDecoration decoration);
controller.addLineDecorations(List<LineDecoration> decorations);
controller.removeLineDecoration(String id);
controller.addGutterDecoration(GutterDecoration decoration);
controller.addGutterDecorations(List<GutterDecoration> decorations);
controller.removeGutterDecoration(String id);
controller.clearGutterDecorations();
// Ghost text (inline suggestions)
controller.setGhostText(GhostText ghostText);
controller.clearGhostText();
// File operations
controller.saveFile();
// Navigation
controller.pressLeftArrowKey(isShiftPressed: false);
controller.pressRightArrowKey(isShiftPressed: false);
controller.pressUpArrowKey(isShiftPressed: false);
controller.pressDownArrowKey(isShiftPressed: false);
controller.pressHomeKey(isShiftPressed: false);
controller.pressEndKey(isShiftPressed: false);
controller.pressDocumentHomeKey(isShiftPressed: false);
controller.pressDocumentEndKey(isShiftPressed: false);
controller.pressWordLeftArrowKey(isShiftPressed: false);
controller.pressWordRightArrowKey(isShiftPressed: false);
There are more methods available in the CodeForgeController API. You can see the complete list here
GutterStyle({
TextStyle? lineNumberStyle,
Color? backgroundColor,
double? gutterWidth,
IconData foldedIcon,
IconData unfoldedIcon,
double? foldingIconSize,
Color? foldedIconColor,
Color? unfoldedIconColor,
Color? activeLineNumberColor,
Color? inactiveLineNumberColor,
Color errorLineNumberColor,
Color warningLineNumberColor,
Color? foldedLineHighlightColor,
})CodeSelectionStyle({
Color? cursorColor,
Color selectionColor,
Color cursorBubbleColor,
})SuggestionStyle(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
backgroundColor: Colors.grey[900]!,
focusColor: Colors.blue.withOpacity(0.3),
hoverColor: Colors.blue.withOpacity(0.1),
splashColor: Colors.blue.withOpacity(0.2),
textStyle: TextStyle(color: Colors.white),
)HoverDetailsStyle(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
backgroundColor: Colors.grey[850]!,
focusColor: Colors.blue.withOpacity(0.3),
hoverColor: Colors.blue.withOpacity(0.1),
splashColor: Colors.blue.withOpacity(0.2),
textStyle: TextStyle(color: Colors.white),
)matchHighlightStyle: const MatchHighlightStyle(
currentMatchStyle: TextStyle(
backgroundColor: Color(0xFFFFA726),
),
otherMatchStyle: TextStyle(
backgroundColor: Color(0x55FFFF00),
),
),Controls which LSP features are enabled during language server initialization.
// Pass to LspSocketConfig or LspStdioConfig
final lspConfig = LspSocketConfig(
workspacePath: "/path/to/workspace",
languageId: "dart",
serverUrl: "ws://localhost:5656",
capabilities: LspClientCapabilities(
semanticHighlighting: true, // Semantic token highlighting
codeCompletion: true, // Code completion suggestions
hoverInfo: true, // Hover documentation
codeAction: true, // Code actions and quick fixes
signatureHelp: true, // Signature help
documentColor: true, // Document color detection
documentHighlight: true, // Symbol occurrence highlighting
codeFolding: true, // Code folding ranges
inlayHint: true, // Inlay hints
goToDefinition: true, // Go to definition
rename: true, // Symbol renaming
),
);CodeForge supports a variety of keyboard shortcuts for efficient editing:
- Ctrl+C — Copy selected text.
- Ctrl+X — Cut selected text.
- Ctrl+V — Paste text.
- Ctrl+A — Select all text.
- Ctrl+D — Duplicate current line.
- Ctrl+Z — Undo last action.
- Ctrl+Y — Redo last action.
- Ctrl+Backspace — Delete word backward.
- Ctrl+Delete — Delete word forward.
- Ctrl+Arrow Left — Move cursor to previous word.
- Ctrl+Arrow Right — Move cursor to next word.
- Ctrl+Shift+Arrow Left — Select to previous word.
- Ctrl+Shift+Arrow Right — Select to next word.
- Ctrl+Shift+Arrow Up — Move current line up.
- Ctrl+Shift+Arrow Down — Move current line down.
- Tab — Indent current line or accept AI completion/suggestion.
- Shift+Tab — Unindent current line.
- Ctrl+. — Show available LSP code actions.
- Ctrl + Shift + Space — Show available LSP signature help.
- Ctrl + Alt — Show LSP inlay hints.
- Arrow Up/Down — Navigate through suggestions.
- Enter/Tab — Accept current suggestion.
- Escape — Close suggestions or hover details.
- Shift+Arrow Keys — Extend selection.
- Shift+Home — Select to line start.
- Shift+End — Select to line end.
- Ctrl + F — Show search bar.
- Ctrl + H — Show replace bar.
Contributions are welcome! Whether it's bug fixes, new features, or documentation improvements.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- re_highlight — Syntax highlighting
- markdown_widget — Markdown rendering
- web_socket_channel — WebSocket support
Built with ❤️ for the Flutter community