Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
5b8bcbc
KTNB-1205: Support Jupyter Widgets - platform and 5 kinds of widgets
ileasile Dec 16, 2025
70494cb
KTNB-1205: Extract widget factory management into `WidgetFactoryRegis…
ileasile Dec 17, 2025
bdce718
KTNB-1205: Refactor widget initialization to use WidgetFactoryRegistr…
ileasile Dec 18, 2025
2168f29
KTNB-1205: Pass `WidgetManager` as a constructor parameter to WidgetM…
ileasile Dec 19, 2025
5260224
KTNB-1205: Extract WidgetManager interface
ileasile Dec 19, 2025
1a48b5d
KTNB-1205: Add separate integration module and README
ileasile Dec 19, 2025
05f6492
KTNB-1205: Fix bugs according to codex review
ileasile Dec 22, 2025
3dcdcd9
KTNB-1205: Fix bugs according to codex review
ileasile Dec 22, 2025
a59a70f
KTNB-1205: Add generator module and schema
ileasile Dec 22, 2025
8d1952d
KTNB-1205: Replace handwritten widget definitions with generated widg…
ileasile Dec 24, 2025
160bd40
KTNB-1205: Refactor widget generation to improve clarity, consistency…
ileasile Dec 25, 2025
e44a392
KTNB-1205: Replace widget-specific enums with generated reusable enum…
ileasile Dec 25, 2025
39f3627
KTNB-1205: Add detailed property descriptions to widget definitions a…
ileasile Dec 25, 2025
6c50e95
KTNB-1205: Refactor widget generator to modularize property type hand…
ileasile Dec 26, 2025
5592116
KTNB-1205: Remove unused widget specs and related functions, clean up…
ileasile Dec 26, 2025
61cea02
KTNB-1205: Add widgets-tests module with tests for widget comm messag…
ileasile Dec 26, 2025
9da020d
KTNB-1205: Add tests for widget state updates, buffer handling, and c…
ileasile Dec 26, 2025
5c0f7e2
KTNB-1205: Add tests for widget display serialization and validation …
ileasile Dec 27, 2025
85a5ccc
KTNB-1205: Import enum package by default
ileasile Dec 27, 2025
9539119
KTNB-1205: Add tests for primitive type serialization/deserialization…
ileasile Dec 27, 2025
be4d6d9
KTNB-1205: Handle missing widget ID during serialization in WidgetRef…
ileasile Dec 27, 2025
8b2c734
KTNB-1205: Refactor widget state synchronization to distinguish front…
ileasile Dec 27, 2025
efae388
KTNB-1205: Update widgets to distinguish frontend-initialized and bac…
ileasile Dec 27, 2025
a4cde0f
KTNB-1205: Make layout and style properties nullable, update widget p…
ileasile Dec 27, 2025
4d3620b
KTNB-1205: Transition to nullable property initialization for primiti…
ileasile Dec 27, 2025
da7cf38
KTNB-1205: Update dependencies for widgets modules to use `api` where…
ileasile Dec 27, 2025
3c3734c
KTNB-1205: Add `echoUpdate` support for selective property updates; i…
ileasile Dec 27, 2025
06ae94d
KTNB-1205: Refactor widget tests to use helper methods for event asse…
ileasile Dec 27, 2025
b6c6e4c
KTNB-1205: Support `Number` type for `step` property in `TimeWidget` …
ileasile Dec 27, 2025
4dd9c4a
KTNB-1205: Refactor widget property handling to use specialized nulla…
ileasile Dec 27, 2025
7366b2b
KTNB-1205: Update widgets README to include new modules, add developm…
ileasile Dec 27, 2025
663d774
KTNB-1205: Remove widget references on comm close to prevent memory l…
ileasile Dec 27, 2025
458ccf5
KTNB-1205: Introduce union types for widget properties, refactor prop…
ileasile Dec 27, 2025
c49593c
KTNB-1205: Add support for sending and receiving custom messages in w…
ileasile Dec 27, 2025
dade110
KTNB-1205: Update widget version handling to include patch version, u…
ileasile Dec 27, 2025
99d7451
KTNB-1205: Fix widget version inconsistency by using `viewModuleVersi…
ileasile Dec 27, 2025
09ca3e2
KTNB-1205: Replace `error` with `throw NotImplementedError` for excep…
ileasile Jan 15, 2026
2cd3f98
added widgets.ipynb example notebook similar to the ipwidgets example…
Jolanrensen Jan 8, 2026
0df0c77
KTNB-1205: Refactor `BufferPathsSerializer` to handle only `Int` for …
ileasile Jan 15, 2026
55722a5
KTNB-1205: Reformat `NotebookTests` and `.editorconfig` for consisten…
ileasile Jan 15, 2026
7c99586
Update misc.xml with Project JDK settings
ileasile Jan 15, 2026
061c15e
KTNB-1205: Remove unused `byMap` and `stopAfter` functions in `Notebo…
ileasile Jan 15, 2026
98adede
Add suppression for EditorConfig key correctness inspections in `.edi…
ileasile Jan 15, 2026
6d6ad5b
Remove reference to the deleted widget
ileasile Jan 16, 2026
92f522b
KTNB-1205: Add more possibilities for manual amending of generated en…
ileasile Jan 16, 2026
7b39095
KTNB-1205: Add `IntRange` and `ClosedRange<Double>` and `PairType` su…
ileasile Jan 17, 2026
c582a9a
Add `setup` lambda to widget creation methods for customization
ileasile Jan 17, 2026
762d797
KTNB-1205: Non-nullable types by default for array elements, base for…
ileasile Jan 17, 2026
d813b1f
KTNB-1205: Move options package
ileasile Jan 17, 2026
0752dc1
KTNB-1205: Add docs
ileasile Jan 17, 2026
973b1a6
KTNB-1205: Add more docs
ileasile Jan 17, 2026
08c402c
KTNB-1205: Add test for outputs
ileasile Jan 17, 2026
6bddf03
KTNB-1205: Structure tests
ileasile Jan 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# noinspection EditorConfigKeyCorrectness
[*.kt]
ktlint_standard_filename = disabled

[**/build/generated/**]
# noinspection EditorConfigKeyCorrectness
[**/generated/**]
ktlint = disabled
generated_code = true
ij_formatter_enabled = false
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Each integration lives in the `integrations/` directory and has its own README.
- [IntelliJ Platform](integrations/intellij-platform/README.md) — interactive access to IntelliJ Platform APIs from a running IDE process.
- [HTTP Utilities](integrations/http-util/README.md) — JSON/serialization helpers and Ktor HTTP client wrappers for notebooks.
- [Database](integrations/database/README.md) — helpers for configuring JDBC DataSources and working with Databases.
- [Widgets](integrations/widgets/README.md) — ipywidgets API for Kotlin notebooks.

## Contributing

Expand Down
9 changes: 8 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
alias(libs.plugins.publisher)
alias(libs.plugins.buildconfig)
alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.ktlint) apply false
alias(libs.plugins.ktlint)
}

version =
Expand All @@ -16,6 +16,13 @@ allprojects {
version = rootProject.version

plugins.apply("org.jlleitschuh.gradle.ktlint")
ktlint {
filter {
exclude { entry ->
entry.file.toString().contains("generated")
}
}
}

repositories {
mavenCentral()
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# https://intellij-support.jetbrains.com/hc/en-us/articles/206544879-Selecting-the-JDK-version-the-IDE-will-run-under
jvmTarget = "17"
kotlin = "2.2.20"
kotlin-jupyter = "0.15.1-668"
kotlin-jupyter = "0.15.3-779-1"
publishPlugin = "2.2.0-dev-71"
intellijPlatformGradlePlugin = "2.10.3"
intellijPlatform = "253-EAP-SNAPSHOT" # TODO: lower to 2025.1.3 GA whenever released with required changes
Expand Down
4 changes: 0 additions & 4 deletions integrations/intellij-platform/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ plugins {
val spaceUsername: String by properties
val spaceToken: String by properties

allprojects {
version = rootProject.version
}

tasks.processJupyterApiResources {
libraryProducers = listOf("org.jetbrains.kotlinx.jupyter.intellij.IntelliJPlatformJupyterIntegration")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package org.jetbrains.kotlinx.jupyter.intellij

import com.intellij.jupyter.core.executor.JupyterExecutionListener
import com.intellij.jupyter.core.jupyter.connections.action.JupyterRestartKernelListener
import com.intellij.jupyter.core.jupyter.connections.execution.core.JupyterNotebookSession
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.application.ApplicationNamesInfo
Expand Down Expand Up @@ -48,7 +47,7 @@ class IntelliJPlatformJupyterIntegration : JupyterIntegration() {

val productVersion = ApplicationInfo.getInstance().run { "$majorVersion.$minorVersion" }
if (productVersion.toVersion() >= MINIMAL_SUPPORTED_IDE_VERSION) {
initializeDisposable(notebook)
initializeDisposable()
initializeIntelliJPlatformClassloader(notebook)
} else {
val productName = ApplicationNamesInfo.getInstance().fullProductName
Expand Down Expand Up @@ -95,7 +94,7 @@ class IntelliJPlatformJupyterIntegration : JupyterIntegration() {
}.excludeUnwantedClasspathEntries()
}

private fun KotlinKernelHost.initializeDisposable(notebook: Notebook) {
private fun KotlinKernelHost.initializeDisposable() {
fun disposeIntegration() {
Disposer.dispose(notebookDisposable)
displayText("IntelliJ Platform integration is disposed")
Expand All @@ -112,16 +111,6 @@ class IntelliJPlatformJupyterIntegration : JupyterIntegration() {
},
)
} catch (_: LinkageError) {
val topic = JupyterRestartKernelListener.TOPIC
requireNotNull(currentProjectFromNotebook(notebook))
.messageBus
.connect(notebookDisposable)
.subscribe(
topic,
JupyterRestartKernelListener {
disposeIntegration()
},
)
}
}

Expand Down
46 changes: 46 additions & 0 deletions integrations/widgets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![Kotlin experimental stability](https://img.shields.io/badge/project-experimental-kotlin.svg?colorA=555555&colorB=AC29EC&label=&logo=kotlin&logoColor=ffffff&logoWidth=10)](https://kotlinlang.org/docs/components-stability.html)

# Kotlin Notebook Widgets Integration

This integration provides a collection of interactive widgets for Kotlin Notebooks, such as sliders, labels, and more. It allows you to create a richer, more interactive experience within your notebooks.

## Usage

Use this API through the `%use widgets` magic command in a Kotlin Notebook.

```kotlin
%use widgets

val slider = intSliderWidget().apply {
min = 0
max = 100
value = 50
description = "Select a value:"
}

val label = labelWidget().apply {
value = "Current value: ${slider.value}"
}

// Display the slider
slider
```

## Module structure

This project consists of the following modules:

- `widgets-api`: Contains the core widget implementations, protocols, and model definitions.
- `widgets-jupyter`: Provides the integration logic and useful helpers for Kotlin Jupyter notebooks.
- `widgets-generator`: Generates widget models from `schema.json`.
- `widgets-tests`: Contains integration tests for widgets.

## Development

Most widgets are automatically generated from a schema.
To regenerate widgets after changing `schema.json` or the generator itself, run:

```bash
./gradlew :integrations:widgets:widgets-generator:generateWidgets
```
24 changes: 24 additions & 0 deletions integrations/widgets/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import org.jetbrains.kotlinx.publisher.apache2
import org.jetbrains.kotlinx.publisher.githubRepo

plugins {
alias(libs.plugins.publisher)
}

kotlinPublications {
pom {
githubRepo("Kotlin", "kotlin-notebook-integrations")
inceptionYear = "2025"
licenses {
apache2()
}
developers {
developer {
id.set("kotlin-jupyter-team")
name.set("Kotlin Jupyter Team")
organization.set("JetBrains")
organizationUrl.set("https://www.jetbrains.com")
}
}
}
}
Binary file added integrations/widgets/notebooks/WidgetArch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
152 changes: 152 additions & 0 deletions integrations/widgets/notebooks/output.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "1dc6dfe0338edca7",
"metadata": {
"ExecuteTime": {
"end_time": "2026-01-16T10:53:58.196356Z",
"start_time": "2026-01-16T10:53:57.656370Z"
},
"executionRelatedData": {
"compiledClasses": [
"Line_3_jupyter",
"Line_4_jupyter",
"Line_5_jupyter",
"Line_6_jupyter",
"Line_7_jupyter"
]
},
"tags": [
"skiptest"
]
},
"outputs": [],
"source": [
"USE {\n",
" repositories { mavenLocal() }\n",
" dependencies {\n",
" implementation(\"org.jetbrains.kotlinx:kotlin-jupyter-widgets-jupyter:0.3.0-1-SNAPSHOT\")\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "fc0a3dd0f8d182da",
"metadata": {
"ExecuteTime": {
"end_time": "2026-01-16T10:54:15.513572Z",
"start_time": "2026-01-16T10:54:15.442978Z"
},
"executionRelatedData": {
"compiledClasses": [
"Line_8_jupyter"
]
}
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b3cd2c4b-33e9-4410-9dc4-863a95686d8b",
"version_major": 1,
"version_minor": 0
},
"text/html": [
"OutputModel(id=b3cd2c4b-33e9-4410-9dc4-863a95686d8b)"
]
},
"metadata": {},
"output_type": "display_data",
"jetTransient": {}
}
],
"source": [
"val out = outputWidget()\n",
"DISPLAY(out)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "b15d36a922b1c5cf",
"metadata": {
"ExecuteTime": {
"end_time": "2026-01-16T10:54:41.738265Z",
"start_time": "2026-01-16T10:54:41.684457Z"
},
"executionRelatedData": {
"compiledClasses": [
"Line_9_jupyter"
]
}
},
"outputs": [],
"source": [
"out.withScope {\n",
" DISPLAY(\"helloo\")\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "a44f5399f0d67f60",
"metadata": {
"ExecuteTime": {
"end_time": "2026-01-16T10:54:48.619173Z",
"start_time": "2026-01-16T10:54:48.572730Z"
},
"executionRelatedData": {
"compiledClasses": [
"Line_10_jupyter"
]
}
},
"outputs": [
{
"data": {
"text/plain": [
"[{output_type=display_data, data={text/plain=helloo}, metadata={}}]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"out.outputs"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "90094eb07622bfb5",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "2.2.20"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading