Skip to content

Latest commit

 

History

History
200 lines (147 loc) · 5.32 KB

File metadata and controls

200 lines (147 loc) · 5.32 KB

SweetLine Java 22 (FFM) API

This document describes the Java 22 FFM wrapper in platform/Java22/sweetline.


Overview

  • Package: com.qiplat.sweetline
  • Binding style: Java 22 Foreign Function & Memory (FFM) over SweetLine C API
  • Demo project: platform/Java22/demo (Swing)

Dependency

Maven

<dependency>
  <groupId>com.qiplat</groupId>
  <artifactId>sweetline-ffm</artifactId>
  <version>1.2.4</version>
</dependency>

Gradle

// build.gradle
implementation 'com.qiplat:sweetline-ffm:1.2.4'

Requirements

  • JDK 22
  • Runtime flags:
    • --enable-preview
    • --enable-native-access=ALL-UNNAMED
  • Native library (sweetline) must be loadable (see Native Loading)

Build and Run

cd platform/Java22
./gradlew :sweetline:build
./gradlew :demo:run

Core Types

  • HighlightConfig(boolean showIndex, boolean inlineStyle)
  • HighlightEngine
  • Document (AutoCloseable)
  • TextAnalyzer (AutoCloseable)
  • DocumentAnalyzer (AutoCloseable)
  • TextPosition, TextRange, TextLineInfo
  • TokenSpan, LineHighlight, DocumentHighlight
  • LineRange, DocumentHighlightSlice
  • IndentGuideLine, IndentGuideResult, LineScopeState
  • SyntaxCompileError

Note:

  • HighlightConfig in Java 22 currently includes showIndex and inlineStyle.

HighlightEngine

public class HighlightEngine implements AutoCloseable {
    public HighlightEngine(HighlightConfig config);
    public HighlightEngine();

    public void registerStyleName(String styleName, int styleId);
    public String getStyleName(int styleId);
    public void defineMacro(String macroName);
    public void undefineMacro(String macroName);

    public void compileSyntaxFromJson(String syntaxJson) throws SyntaxCompileError;
    public void compileSyntaxFromFile(String path) throws SyntaxCompileError;

    public TextAnalyzer createAnalyzerBySyntaxName(String syntaxName);
    public TextAnalyzer createAnalyzerByFileName(String fileName);
    public DocumentAnalyzer loadDocument(Document document);

    public void close();
}

TextAnalyzer

public class TextAnalyzer implements AutoCloseable {
    public DocumentHighlight analyzeText(String text);
    public LineAnalyzeResult analyzeLine(String text, TextLineInfo info);
    public IndentGuideResult analyzeIndentGuides(String text);
    public void close();
}

DocumentAnalyzer

public class DocumentAnalyzer implements AutoCloseable {
    public DocumentHighlight analyze();
    public DocumentHighlight analyzeIncremental(TextRange range, String newText);
    public DocumentHighlightSlice analyzeLineRange(LineRange visibleRange);
    public DocumentHighlightSlice analyzeIncrementalInLineRange(
            TextRange range, String newText, LineRange visibleRange);
    public DocumentHighlightSlice getHighlightSlice(LineRange visibleRange);
    public IndentGuideResult analyzeIndentGuides();
    public void close();
}

analyzeLineRange(...) analyzes enough lines from the current managed document state to satisfy the requested visible range. analyzeIncrementalInLineRange(...) applies a patch and immediately returns the requested slice. getHighlightSlice(...) reads a visible slice from the latest cached result after analyze() or analyzeIncremental(...).


Native Loading

SweetLineNative resolves native library in this order:

  1. System property sweetline.lib.path
  2. Common source/build output directories
  3. JAR resource extraction fallback (NativeLibraryExtractor.extractToDefaultDir())
  4. java.library.path / System.loadLibrary

You can explicitly set:

-Dsweetline.lib.path=/path/to/native/lib/dir

JAR packaging scenario:

import com.qiplat.sweetline.NativeLibraryExtractor;
import java.nio.file.Path;

Path libPath = NativeLibraryExtractor.extractToDefaultDir();

Complete Example

import com.qiplat.sweetline.*;

String sourceCode = "public class Demo {}";

try (HighlightEngine engine = new HighlightEngine(new HighlightConfig(true, false))) {
    engine.registerStyleName("keyword", 1);
    engine.registerStyleName("string", 2);
    engine.compileSyntaxFromFile("syntaxes/java.json");

    try (TextAnalyzer textAnalyzer = engine.createAnalyzerBySyntaxName("java")) {
        if (textAnalyzer != null) {
            DocumentHighlight full = textAnalyzer.analyzeText(sourceCode);
        }
    }

    try (Document document = new Document("file:///Demo.java", sourceCode)) {
        DocumentAnalyzer analyzer = engine.loadDocument(document);
        if (analyzer != null) {
            try (analyzer) {
                DocumentHighlight initial = analyzer.analyze();

                TextRange change = new TextRange(
                        new TextPosition(0, 13),
                        new TextPosition(0, 17));
                DocumentHighlight updated = analyzer.analyzeIncremental(change, "Sample");
                DocumentHighlightSlice cachedVisible = analyzer.getHighlightSlice(
                        new LineRange(0, 80));

                DocumentHighlightSlice visible = analyzer.analyzeIncrementalInLineRange(
                        change,
                        "Sample",
                        new LineRange(0, 80));

                IndentGuideResult guides = analyzer.analyzeIndentGuides();
            }
        }
    }
}