Files
intellij-slint/docs/plans/2026-01-29-slint-lsp-integration.md
2026-01-29 20:32:59 +08:00

13 KiB

Slint LSP Integration Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Implement complete Slint LSP integration into IntelliJ IDEA with file type system, LSP server configuration, and syntax highlighting.

Architecture: Use IntelliJ's built-in LSP framework to connect to Slint LSP server. Register .slint file type, configure LSP server descriptor, and add TextMate-based syntax highlighting.

Tech Stack: Kotlin, IntelliJ Platform SDK, LSP API, TextMate grammar


Task 1: Create Slint Language Definition

Files:

  • Create: src/main/kotlin/me/zhouxi/slint/lang/SlintLanguage.kt

Step 1: Create SlintLanguage object

Create the file with this content:

package me.zhouxi.slint.lang

import com.intellij.lang.Language

object SlintLanguage : Language("Slint") {
    override fun getDisplayName(): String = "Slint"
}

Step 2: Verify compilation

Run: ./gradlew compileKotlin Expected: BUILD SUCCESSFUL

Step 3: Commit

git add src/main/kotlin/me/zhouxi/slint/lang/SlintLanguage.kt
git commit -m "feat: add Slint language definition"

Task 2: Create Slint File Type

Files:

  • Create: src/main/kotlin/me/zhouxi/slint/lang/SlintFileType.kt

Step 1: Create SlintFileType object

Create the file with this content:

package me.zhouxi.slint.lang

import com.intellij.openapi.fileTypes.LanguageFileType
import me.zhouxi.slint.icons.SlintIcons
import javax.swing.Icon

object SlintFileType : LanguageFileType(SlintLanguage) {
    override fun getName(): String = "Slint"

    override fun getDescription(): String = "Slint UI file"

    override fun getDefaultExtension(): String = "slint"

    override fun getIcon(): Icon = SlintIcons.Primary
}

Step 2: Verify compilation

Run: ./gradlew compileKotlin Expected: BUILD SUCCESSFUL

Step 3: Commit

git add src/main/kotlin/me/zhouxi/slint/lang/SlintFileType.kt
git commit -m "feat: add Slint file type definition"

Task 3: Register File Type in plugin.xml

Files:

  • Modify: src/main/resources/META-INF/plugin.xml

Step 1: Add fileType extension

Add this inside the <extensions defaultExtensionNs="com.intellij"> block:

<fileType
    name="Slint"
    implementationClass="me.zhouxi.slint.lang.SlintFileType"
    fieldName="INSTANCE"
    language="Slint"
    extensions="slint"/>

The complete extensions block should look like:

<extensions defaultExtensionNs="com.intellij">
    <fileType
        name="Slint"
        implementationClass="me.zhouxi.slint.lang.SlintFileType"
        fieldName="INSTANCE"
        language="Slint"
        extensions="slint"/>
    <platform.lsp.serverSupportProvider implementation="me.zhouxi.slint.lsp.SlintLspServerSupportProvider"/>
</extensions>

Step 2: Verify plugin configuration

Run: ./gradlew verifyPluginProjectConfiguration Expected: BUILD SUCCESSFUL

Step 3: Commit

git add src/main/resources/META-INF/plugin.xml
git commit -m "feat: register Slint file type in plugin.xml"

Task 4: Update LSP Server Descriptor

Files:

  • Modify: src/main/kotlin/me/zhouxi/slint/lsp/SlintLspServerSupportProvider.kt

Step 1: Add import for SlintFileType

Add this import at the top:

import me.zhouxi.slint.lang.SlintFileType

Step 2: Rename FooLspServerDescriptor to SlintLspServerDescriptor

Change line 20 from:

serverStarter.ensureServerStarted(FooLspServerDescriptor(project))

To:

serverStarter.ensureServerStarted(SlintLspServerDescriptor(project))

Change line 34 from:

private class FooLspServerDescriptor(project: Project) : ProjectWideLspServerDescriptor(project, "Slint") {

To:

private class SlintLspServerDescriptor(project: Project) : ProjectWideLspServerDescriptor(project, "Slint") {

Step 3: Update file type checking to use SlintFileType

Change line 19 from:

if (file.extension == "slint") {

To:

if (file.fileType == SlintFileType) {

Change line 35 from:

override fun isSupportedFile(file: VirtualFile) = file.extension == "slint"

To:

override fun isSupportedFile(file: VirtualFile) = file.fileType == SlintFileType

Step 4: Verify compilation

Run: ./gradlew compileKotlin Expected: BUILD SUCCESSFUL

Step 5: Commit

git add src/main/kotlin/me/zhouxi/slint/lsp/SlintLspServerSupportProvider.kt
git commit -m "refactor: use SlintFileType for type-safe file detection"

Task 5: Download TextMate Grammar File

Files:

  • Create: src/main/resources/textmate/slint.tmLanguage.json

Step 1: Create textmate directory

Run: mkdir -p src/main/resources/textmate

Step 2: Download Slint TextMate grammar

Run:

curl -o src/main/resources/textmate/slint.tmLanguage.json \
  https://raw.githubusercontent.com/slint-ui/slint/master/editors/vscode/syntaxes/slint.tmLanguage.json

Expected: File downloaded successfully

Step 3: Verify file exists and is valid JSON

Run: cat src/main/resources/textmate/slint.tmLanguage.json | head -20 Expected: Should see JSON content starting with { and containing "scopeName": "source.slint"

Step 4: Commit

git add src/main/resources/textmate/slint.tmLanguage.json
git commit -m "feat: add Slint TextMate grammar for syntax highlighting"

Task 6: Create TextMate Bundle Provider

Files:

  • Create: src/main/kotlin/me/zhouxi/slint/lang/syntax/SlintTextMateProvider.kt

Step 1: Create syntax directory

Run: mkdir -p src/main/kotlin/me/zhouxi/slint/lang/syntax

Step 2: Create SlintTextMateProvider class

Create the file with this content:

package me.zhouxi.slint.lang.syntax

import org.jetbrains.plugins.textmate.api.TextMateBundle
import org.jetbrains.plugins.textmate.api.TextMateBundleProvider

class SlintTextMateProvider : TextMateBundleProvider {
    override fun getBundles(): List<TextMateBundle> {
        return listOf(
            TextMateBundle(
                "Slint",
                "textmate/slint.tmLanguage.json",
                SlintTextMateProvider::class.java.classLoader
            )
        )
    }
}

Step 3: Verify compilation

Run: ./gradlew compileKotlin Expected: BUILD SUCCESSFUL

Step 4: Commit

git add src/main/kotlin/me/zhouxi/slint/lang/syntax/SlintTextMateProvider.kt
git commit -m "feat: add TextMate bundle provider for Slint syntax highlighting"

Task 7: Register TextMate Bundle Provider

Files:

  • Modify: src/main/resources/META-INF/plugin.xml

Step 1: Add textMate.bundleProvider extension

Add this inside the <extensions defaultExtensionNs="com.intellij"> block:

<textMate.bundleProvider implementation="me.zhouxi.slint.lang.syntax.SlintTextMateProvider"/>

The complete extensions block should now look like:

<extensions defaultExtensionNs="com.intellij">
    <fileType
        name="Slint"
        implementationClass="me.zhouxi.slint.lang.SlintFileType"
        fieldName="INSTANCE"
        language="Slint"
        extensions="slint"/>
    <platform.lsp.serverSupportProvider implementation="me.zhouxi.slint.lsp.SlintLspServerSupportProvider"/>
    <textMate.bundleProvider implementation="me.zhouxi.slint.lang.syntax.SlintTextMateProvider"/>
</extensions>

Step 2: Verify plugin configuration

Run: ./gradlew verifyPluginProjectConfiguration Expected: BUILD SUCCESSFUL

Step 3: Commit

git add src/main/resources/META-INF/plugin.xml
git commit -m "feat: register TextMate bundle provider in plugin.xml"

Task 8: Build and Test Plugin

Files:

  • Create: test-files/hello.slint (for manual testing)

Step 1: Create test directory and sample Slint file

Run:

mkdir -p test-files
cat > test-files/hello.slint << 'EOF'
import { Button, VerticalBox } from "std-widgets.slint";

export component HelloWorld inherits Window {
    width: 400px;
    height: 300px;

    VerticalBox {
        alignment: center;

        Text {
            text: "Hello, World!";
            font-size: 24px;
        }

        Button {
            text: "Click me";
            clicked => {
                debug("Button clicked!");
            }
        }
    }
}
EOF

Step 2: Build the plugin

Run: ./gradlew buildPlugin Expected: BUILD SUCCESSFUL, plugin ZIP created in build/distributions/

Step 3: Run plugin in sandbox IDE

Run: ./gradlew runIde Expected: IntelliJ IDEA opens with plugin installed

Step 4: Manual testing checklist

In the sandbox IDE:

  1. Open test-files/hello.slint
  2. Verify: File icon shows Slint logo
  3. Verify: Syntax highlighting is applied (keywords, strings, comments colored)
  4. Verify: LSP server starts (check status bar widget)
  5. Verify: Type Butt and trigger completion (Ctrl+Space) - should suggest Button
  6. Verify: Hover over Button - should show documentation
  7. Verify: Ctrl+Click on Button - should jump to definition
  8. Verify: Introduce syntax error (e.g., remove semicolon) - should show red underline
  9. Verify: Format code (Ctrl+Alt+L) - should format the file

Step 5: Document test results

Create a file documenting what works:

cat > test-files/TEST_RESULTS.md << 'EOF'
# Slint LSP Integration Test Results

Date: 2026-01-29

## Test Environment
- IntelliJ IDEA: 2025.2.4
- Slint LSP Version: 1.14.1
- Plugin Version: 1.0-SNAPSHOT

## Test Results

### File Type Recognition
- [ ] .slint files show Slint icon
- [ ] File type is recognized as "Slint"

### Syntax Highlighting
- [ ] Keywords highlighted (import, export, component, inherits)
- [ ] Strings highlighted
- [ ] Comments highlighted
- [ ] Properties highlighted

### LSP Features
- [ ] LSP server starts automatically
- [ ] Code completion works
- [ ] Hover documentation works
- [ ] Goto definition works
- [ ] Diagnostics show errors/warnings
- [ ] Code formatting works
- [ ] Find references works
- [ ] Rename refactoring works

## Issues Found
(Document any issues here)

## Notes
(Any additional observations)
EOF

Step 6: Commit test files

git add test-files/
git commit -m "test: add sample Slint file and test results template"

Task 9: Update CLAUDE.md Documentation

Files:

  • Modify: CLAUDE.md

Step 1: Add testing section to CLAUDE.md

Add this section before "## Development Notes":

## Testing the Plugin

### Manual Testing

1. **Build and run in sandbox:**
   ```bash
   ./gradlew runIde
  1. Test with sample file:

    • Open test-files/hello.slint
    • Verify file icon, syntax highlighting, and LSP features
  2. Test LSP features:

    • Code completion: Type and press Ctrl+Space
    • Goto definition: Ctrl+Click on symbols
    • Hover: Mouse over symbols
    • Diagnostics: Introduce syntax errors
    • Formatting: Ctrl+Alt+L

Verify LSP Server

Check LSP server status in the status bar (bottom right). Should show "Slint" when a .slint file is open.

Common Issues

  • LSP server not starting: Check that LSP binary exists in sandbox at sandbox/plugins/slint/lsp/slint-lsp-{platform}
  • No syntax highlighting: Verify TextMate grammar file is in resources
  • No completion: Check LSP server logs in idea.log

**Step 2: Commit documentation update**

```bash
git add CLAUDE.md
git commit -m "docs: add testing instructions to CLAUDE.md"

Task 10: Final Verification and Cleanup

Step 1: Run all verification tasks

Run:

./gradlew clean build verifyPlugin

Expected: All tasks complete successfully

Step 2: Check plugin structure

Run: ./gradlew buildPlugin && unzip -l build/distributions/slint-1.0-SNAPSHOT.zip | grep -E "(slint-lsp|\.slint\.tmLanguage)"

Expected: Should see LSP binaries and TextMate grammar in the plugin ZIP

Step 3: Review all changes

Run: git log --oneline --graph

Expected: Should see all commits from this implementation

Step 4: Create final summary commit

git add -A
git commit -m "feat: complete Slint LSP integration with file type, syntax highlighting, and LSP features

- Added SlintLanguage and SlintFileType definitions
- Registered .slint file type with IntelliJ
- Integrated Slint LSP server with type-safe file detection
- Added TextMate-based syntax highlighting
- Included test files and documentation
- All standard LSP features now available: completion, diagnostics, goto definition, hover, formatting, references, rename"

Success Criteria

.slint files recognized by IntelliJ with proper icon Syntax highlighting works using TextMate grammar LSP server starts automatically when .slint file opened Code completion provides suggestions Diagnostics show errors and warnings Goto definition navigates correctly Hover shows documentation Code formatting works Find references works Rename refactoring works Plugin builds and runs in sandbox IDE All changes committed with clear messages

Next Steps (Phase 2)

  • Implement live preview integration (Slint-specific feature)
  • Add project configuration UI
  • Optimize LSP server startup time
  • Add more comprehensive tests