English | 简体中文
SweetLine is a cross-platform, high-performance, and extensible syntax highlighting engine designed for modern code editors and code display scenarios. Built on the Oniguruma regex engine and a finite state machine model, it processes large code files in real-time with accurate syntax highlighting.
- Built on Oniguruma regex engine for fast pattern matching
- Incremental update algorithm that only reanalyzes changed portions, ideal for real-time editor highlighting
- Multi-line state preservation to avoid full document reanalysis
- Finite State Machine (FSM) based model supporting complex syntax rule nesting
- Multiple capture group style mapping for fine-grained highlighting control
- SubStates mechanism for handling nested syntax structures (e.g., generics, template parameters)
- Zero-width match support for context-sensitive state transitions
- JSON-based syntax rule configuration – add new language support without writing code
- Variable substitution,
fragments(include/includes), and pattern reuse to reduce rule redundancy 100+built-in syntax rule files covering mainstream languages, markup, configuration, template, and domain-specific syntaxes
- Core engine written in C++17
- C API wrapper for easy FFI integration
- Native support for Android (JNI), Java 22 (FFM), Flutter/Dart (FFI), WebAssembly (Emscripten), HarmonyOS (NAPI), .NET/WinForms (P/Invoke), and Apple platforms
- Supports Windows, Linux, macOS, mobile platforms, and other desktop scenarios
┌────────────────────────────────────────────────────────────────────────────────────┐
│ SweetLine Architecture │
├────────────────────────────────────────────────────────────────────────────────────┤
│ Application / Platform Bindings │
│ Android(JNI) | Java22(FFM) | Flutter(Dart FFI) | .NET/C#(P/Invoke) │
│ WASM(Emscripten) | HarmonyOS(NAPI) | Apple(Swift/ObjC) │
│ C API(FFI) | C++ Native API │
├────────────────────────────────────────────────────────────────────────────────────┤
│ SweetLine C++ Core (C++17) │
│ │
│ ┌──────────────────────┐ ┌──────────────────────────────┐ │
│ │ HighlightEngine │ -----> │ SyntaxRule Compiler (JSON) │ │
│ └──────────┬───────────┘ └──────────────────────────────┘ │
│ │ │
│ ┌────────▼─────────┐ ┌──────────────────────┐ │
│ │ TextAnalyzer │ │ DocumentAnalyzer │ │
│ │ (Full Scan) │ │ (Incremental) │ │
│ └────────┬─────────┘ └──────────┬───────────┘ │
│ │ │ │
│ │ ┌────────▼─────────┐ │
│ │ │ Document Model │ │
│ │ │ (Managed Text) │ │
│ │ └──────────────────┘ │
│ │ │
│ └──────────────┬───────────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Regex + FSM Runtime (Oniguruma + State Machine) │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
│ ▼ │
│ Highlight Result + Scope/Indent Guide Analysis │
└────────────────────────────────────────────────────────────────────────────────────┘
#include "highlight.h"
using namespace sweetline;
// 1. Create highlight engine
auto engine = std::make_shared<HighlightEngine>();
// 2. Compile syntax rules
auto rule = engine->compileSyntaxFromFile("syntaxes/java.json");
// 3. Create document object
auto document = std::make_shared<Document>("example.java", R"(
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
)");
// 4. Load document and analyze
auto analyzer = engine->loadDocument(document);
auto highlight = analyzer->analyze();
// 5. Iterate highlight results
for (size_t i = 0; i < highlight->lines.size(); i++) {
auto& line = highlight->lines[i];
for (auto& span : line.spans) {
// span.range - text range (line/column/index)
// span.style_id - style ID (keyword=1, string=2, ...)
}
}// When the document is edited, only reanalyze the changed portion
TextRange change_range { {2, 4}, {2, 8} };
std::string new_text = "modified";
auto new_highlight = analyzer->analyzeIncremental(change_range, new_text);
LineRange visible_range {100, 60};
// Analyze enough lines to cover the requested visible range
auto analyzed_slice = analyzer->analyzeLineRange(visible_range);
// Read only the visible lines from the latest cached highlight result
auto cached_slice = analyzer->getHighlightSlice(visible_range);
// Or combine patch + visible slice in one call
auto updated_slice = analyzer->analyzeIncrementalInLineRange(change_range, new_text, visible_range);Use analyzeLineRange() when the renderer needs a visible slice and wants SweetLine to analyze enough lines from the current document state first.
Use getHighlightSlice() after analyze() or analyzeIncremental() when the renderer only needs a visible window of lines.
import com.qiplat.sweetline.*;
try (HighlightEngine engine = new HighlightEngine(new HighlightConfig(true, false))) {
engine.compileSyntaxFromFile("syntaxes/java.json");
try (TextAnalyzer analyzer = engine.createAnalyzerByFileName("Example.java")) {
DocumentHighlight result = analyzer.analyzeText(sourceCode);
}
}Java 22 FFM wrapper is located at platform/Java22.
Running code requires native access enabled (for example --enable-native-access=ALL-UNNAMED) and a resolvable SweetLine native library path.
// build.gradle
implementation 'com.qiplat:sweetline:1.2.4'// Create engine
HighlightEngine engine = new HighlightEngine(new HighlightConfig());
// Compile syntax rules
engine.compileSyntaxFromJson(jsonString);
// Full analysis
TextAnalyzer analyzer = engine.createAnalyzerByFileName("MainActivity.java");
DocumentHighlight result = analyzer.analyzeText(sourceCode);
// Iterate results
for (LineHighlight line : result.lines) {
for (TokenSpan span : line.spans) {
// span.range, span.styleId
}
}import createSweetLine from './sweetline.js';
const sl = await createSweetLine();
const config = new sl.HighlightConfig();
const engine = new sl.HighlightEngine(config);
// Compile syntax rules
engine.compileSyntaxFromJson(jsonString);
// Analyze text
const analyzer = engine.createAnalyzerByFileName("main.js");
const highlight = analyzer.analyzeText(sourceCode);
// Iterate results
for (let i = 0; i < highlight.lines.size(); i++) {
const line = highlight.lines.get(i);
for (let j = 0; j < line.spans.size(); j++) {
const span = line.spans.get(j);
// span.range, span.styleId
}
}SweetLine uses JSON to define syntax rules. Here is a simple example:
Routing metadata is file-name based. Use fileName / fileNames for exact base names, fileSuffix / fileSuffixes for suffix matches, and fileNamePattern / fileNamePatterns only when exact names and suffixes are not enough.
{
"name": "myLanguage",
"fileSuffixes": [".mylang"],
"variables": {
"identifier": "[a-zA-Z_]\\w*"
},
"fragments": {
"commonLiterals": [
{ "pattern": "\"(?:[^\"\\\\]|\\\\.)*\"", "style": "string" },
{ "pattern": "//[^\\n]*", "style": "comment" }
]
},
"states": {
"default": [
{
"pattern": "\\b(if|else|while|return)\\b",
"styles": [1, "keyword"]
},
{ "include": "commonLiterals" }
]
}
}For complete syntax rule configuration, see the Syntax Rule Configuration Guide.
If you want to add or refine syntax rules more quickly, you can also use the skill in skills/. The recommended entry is:
sweetline-syntax-profile: the SweetLine syntax-authoring workflow and repository policy for syntax rules, routing, style vocabulary, examples, tests, and demo registration
| Document | Description |
|---|---|
| Syntax Rule Configuration Guide | Detailed guide on writing JSON syntax rule files |
| Engine Comparison Report | Multidimensional comparison with mainstream syntax highlighting engines |
| API Reference (Index) | API entry page and reading order |
| Core API | Core concepts and C++ API |
| C API | C interface for FFI integration |
| macOS Swift API | Swift Package API on macOS |
| iOS Swift API | Swift Package API on iOS |
| Android API | Java/Kotlin API on Android |
| Flutter API | Dart FFI wrapper API |
| Java 22 API | Java 22 FFM API |
| .NET / WinForms API | C# API (P/Invoke wrapper) |
| WebAssembly API | JavaScript/TypeScript API |
| HarmonyOS API | ArkTS/NAPI API usage |
| Build Guide | Multi-platform build commands and options |
| Contributing Guide | How to participate in the project, including using repository skills for faster syntax authoring |
SweetLine provides a grammar pack covering 100+ language and syntax scenarios, including mainstream programming languages, markup languages, configuration formats, template syntaxes, and specialized grammars.
Both the grammars shipped with the repository and developer-authored custom grammars are compiled through HighlightEngine before use, making it easy to adapt SweetLine to different languages, frameworks, and domain-specific scenarios.
See the syntaxes/ directory for the available grammar set, and the Syntax Rule Configuration Guide for authoring details.
- Pre-compile syntax rules: Compile all required syntax rules at application startup; compiled rules are reusable
- Prefer incremental updates: For editor scenarios, use
DocumentAnalyzerincremental analysis instead of full analysis - Optimize regular expressions: Avoid overly complex backtracking-intensive patterns; use
variablesto reuse common patterns - Design state machines carefully: Control the number of states and ensure every state has a clear exit path
We welcome contributions to the SweetLine highlighting engine! If you'd like to participate, feel free to fork the repository, make changes, and submit merge requests. For syntax-related work, we recommend using the skills in skills/ together with the Contributing Guide.




