code_forge
AI 완성, LSP 지원, 구문 강조 및 고급 편집 기능을 갖춘 정교한 코드 에디터 패키지입니다.
Flutter를 사용하여 만든 강력하고 기능이 풍부한 코드 에디터 위젯
{"sdk":"flutter"}^2.3.2+8^0.0.3^3.0.3^1.1.0^2.2.0^2.13.0{"sdk":"flutter"}^6.0.0{"sdk":"flutter"}아래는 영문 원문 스냅샷입니다. 최신 내용은 GitHub에서 확인하세요.
A powerful, feature-rich code editor widget with backend written in rust
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
Pub Version License GitHub Stars Platform
CodeForge Demo
Smooth editing in 1M+ lines of code, tested on a decades old low end PC with pentium dual core CPU and no dedicated graphics card.
CodeForge Demo
LSP based intelligent lazy highlighting on 100k+ lines
[!NOTE]
code_forge does not support Flutter web, as it relies on
dart:iofor core functionality. Use code_forge_web for web support.
[!NOTE]
The debug build is 60% slower than the profile and release builds because of the frequent FFI calls made by the editor to the rust backend, which is expensive in JIT mode. It doesn't affect the AOT mode used in profile and release. So debug builds can get extremely slow and laggy on large files.
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 | Limited |
| LSP Integration | Full support | ❌ |
| AI Completion | Multi-model | ❌ |
| Semantic Tokens | Real-time | ❌ |
| Diagnostics | Inline errors | ❌ |
| Undo/Redo | Smart grouping | Basic |
| Full Theming | Available themes | Limited |
RenderBox and ParagrahBuilder to render text insted of TextField for efficiency.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.
re_highlight package1 . Make sure to install rustup and add it to the $PATH.
2 . Add CodeForge to your pubspec.yaml:
dependencies:
code_forge: ^10.14.0
flutter pub get
await RustLib.init(); in your main function:void main() async {
await RustLib.init(); // Add this line
runApp(const MyApp());
}
Import a theme and a language from the re_highlight package and you are good to go. (Defaults to plain text and lightFlairTheme):
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 Mode(), means plain text
editorTheme: atomOneDarkTheme, // Defaults to lightFlairTheme
),
),
);
}
}
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.
CodeForge: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 the filePath file.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 5656
create 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 the filePath file.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-langserver
Create 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),
),
...
),
scrollbarDecoration: const ScrollbarDecoration(
thumbColor: _editorTheme['root']?.color?.withAlpha(150),
thickness: 15,
lineNumberStyle: TextStyle(
color: _editorTheme['root']?.backgroundColor ?? Colors.black,
fontSize: widget.textStyle?.fontSize ?? 14,
fontFamily: widget.textStyle?.fontFamily,
fontWeight: widget.textStyle?.fontWeight ?? FontWeight.bold,
),
...
);
)
CodeForge(
// Enable/disable features
enableFolding: true, // Code folding
enableGutter: true, // Line numbers
enableGuideLines: true, // Indentation guides
enableGutterDivider: false, // Gutter separator line
enableLocalSuggestions: true, // Enable or disable local word suggestions. False by default.
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 |
extraLanguages |
List<Mode> |
Useful for languages that embed other grammars (for example, TSX using XML/HTML sub-languages) |
keyboardType |
TextInputType |
Type of virtual keyboard |
customCodeSnippets |
List<CustomCodeSnippet>? |
Custom code snippets shown in the suggestion popup |
customContextMenuItems |
List<CustomContextMenu>? |
Custom context items shown in the context menu (The menu shown on right click) |
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);
// Multi-cursor operations
controller.addMultiCursor(int line, int character);
controller.clearMultiCursor();
controller.backspaceAtAllCursors();
controller.insertAtAllCursors(String textToInsert);
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
),
);
This project is licensed under the MIT License - see the LICENSE file for details.
Built with ❤️ for the Flutter community