Skip to content

Commit

Permalink
All commits (need to be split into smaller commits)
Browse files Browse the repository at this point in the history
  • Loading branch information
kitakkun committed Jan 8, 2025
1 parent 65be532 commit c05bb12
Show file tree
Hide file tree
Showing 64 changed files with 2,769 additions and 18 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ plugins {
alias(libs.plugins.buildconfig) apply false
alias(libs.plugins.maven.publish) apply false
alias(libs.plugins.jetbrainsCompose) apply false
alias(libs.plugins.sqldelight) apply false
alias(libs.plugins.intelliJPlatform) apply false
// convention plugin
alias(libs.plugins.backintimeLint) apply false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.kitakkun.backintime.evaluation

import android.app.Application
import com.kitakkun.backintime.demo.flipper.FlipperInitializer
import com.kitakkun.backintime.core.runtime.BackInTimeDebugService
import com.kitakkun.backintime.core.runtime.connector.BackInTimeKtorWebSocketConnector
import com.kitakkun.backintime.core.runtime.getBackInTimeDebugService
import com.kitakkun.backintime.core.runtime.internal.BackInTimeCompilerInternalApi
import com.kitakkun.backintime.evaluation.di.appModule
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
Expand All @@ -11,7 +14,11 @@ class MyApplication : Application() {
override fun onCreate() {
super.onCreate()

FlipperInitializer().init(this)
@OptIn(BackInTimeCompilerInternalApi::class)
val service: BackInTimeDebugService = getBackInTimeDebugService()

service.setConnector(BackInTimeKtorWebSocketConnector(host = "10.0.2.2", port = 50023))
service.startService()

startKoin {
androidLogger()
Expand Down
4 changes: 4 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ include(
":core:websocket:event",
":tooling:model",
":tooling:idea-plugin",
":tooling:database",
":tooling:usecase",
":tooling:ui",
":tooling:shared",
)
27 changes: 27 additions & 0 deletions tooling/database/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
alias(libs.plugins.kotlinJvm)
alias(libs.plugins.sqldelight)
alias(libs.plugins.kotlinSerialization)
}

kotlin {
jvmToolchain(17)
}

sqldelight {
databases {
create("Database") {
packageName.set("com.kitakkun.backintime.tooling.database")
}
}
}

dependencies {
implementation(projects.core.websocket.event)
implementation(projects.tooling.model)
implementation(projects.tooling.shared)
implementation(libs.sqldelight.sqlite.driver)
implementation(libs.sqldelight.coroutines.extensions)
implementation(libs.kotlinx.serialization.json)
testImplementation(libs.kotlin.test)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.kitakkun.backintime.tooling.database

import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList
import com.kitakkun.backintime.tooling.model.InstanceEventData
import com.kitakkun.backintime.tooling.shared.BackInTimeDatabase
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

class BackInTimeDatabaseImpl : BackInTimeDatabase {
companion object {
val instance: BackInTimeDatabaseImpl by lazy { BackInTimeDatabaseImpl() }
}

init {
// Fix no suitable driver found for jdbc:sqlite:
// FYI: https://stackoverflow.com/questions/16725377/unable-to-connect-to-database-no-suitable-driver-found
Class.forName("org.sqlite.JDBC")
}

private val database = createDatabase()
private val instanceEventQueries: InstanceEventQueries = database.instanceEventQueries

override fun saveEvent(sessionId: String, event: InstanceEventData) {
instanceEventQueries.insert(event.eventId, sessionId, event.instanceId, event)
}

override fun selectEventsForInstance(instanceId: String): Flow<List<InstanceEventData>> {
return instanceEventQueries.selectByInstanceId(instanceId).asFlow()
.mapToList(Dispatchers.IO)
.map { it.mapNotNull { it.event } }
}

override fun getAllEventsAsFlow(): Flow<List<InstanceEventData>> = instanceEventQueries.selectAll().asFlow().mapToList(Dispatchers.IO).map { it.mapNotNull { it.event } }

override fun selectEventsForSession(sessionId: String?): Flow<List<InstanceEventData>> {
return if (sessionId == null) {
getAllEventsAsFlow()
} else {
instanceEventQueries.selectBySessionId(sessionId).asFlow().mapToList(Dispatchers.IO).map { it.mapNotNull { it.event } }
}
}

override fun allInstanceIdForSessionAsFlow(sessionId: String): Flow<List<String>> = instanceEventQueries.selectAllInstanceId(sessionId).asFlow().mapToList(Dispatchers.IO)

override fun allEventsForInstanceAsFlow(sessionId: String, instanceId: String): Flow<List<InstanceEventData>> {
return instanceEventQueries.selectAllForInstance(sessionId, instanceId).asFlow().mapToList(Dispatchers.IO).map {
it.mapNotNull { it.event }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.kitakkun.backintime.tooling.database

import app.cash.sqldelight.ColumnAdapter
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
import com.kitakkun.backintime.tooling.model.InstanceEventData
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

private val instanceEventAdapter = object : ColumnAdapter<InstanceEventData, String> {
override fun encode(value: InstanceEventData): String {
return Json.encodeToString(value)
}

override fun decode(databaseValue: String): InstanceEventData {
return Json.decodeFromString(databaseValue)
}
}

fun createDatabase(url: String = JdbcSqliteDriver.IN_MEMORY): Database {
val driver = JdbcSqliteDriver(url)
Database.Schema.create(driver)
return Database(
driver = driver,
instanceEventAdapter = InstanceEvent.Adapter(eventAdapter = instanceEventAdapter),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import com.kitakkun.backintime.tooling.model.InstanceEventData;

CREATE TABLE IF NOT EXISTS instanceEvent (
id TEXT PRIMARY KEY NOT NULL,
sessionId TEXT NOT NULL,
instanceId TEXT NOT NULL,
event TEXT AS InstanceEventData
);

insert:
INSERT OR IGNORE INTO instanceEvent(id, sessionId, instanceId, event) VALUES (?, ?, ?, ?);

selectByInstanceId:
SELECT * FROM instanceEvent WHERE instanceId == ?;

selectAll:
SELECT * FROM instanceEvent;

selectBySessionId:
SELECT * FROM instanceEvent WHERE sessionId == ?;

selectAllInstanceId:
SELECT DISTINCT instanceId FROM instanceEvent WHERE sessionId == ?;

selectAllForInstance:
SELECT * FROM instanceEvent WHERE sessionId == ? AND instanceId == ?;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.kitakkun.backintime.tooling.database

import com.kitakkun.backintime.tooling.model.InstanceEventData
import kotlin.test.Test

class BackInTimeDatabaseImplTest {
@Test
fun test() {
val database = BackInTimeDatabaseImpl()
database.saveEvent("sessionId", InstanceEventData.Unregister(instanceId = "uuid", time = 0L))
}
}
23 changes: 23 additions & 0 deletions tooling/idea-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,42 @@ kotlin {
repositories {
intellijPlatform {
defaultRepositories()
intellijDependencies()
}
mavenCentral()
google()
maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies/")
maven("https://packages.jetbrains.team/maven/p/kpm/public/")
}

dependencies {
intellijPlatform {
create("IC", "2024.3.1")
bundledPlugin("com.intellij.java")
}

implementation(projects.core.websocket.server)
implementation(projects.core.websocket.event)
implementation(projects.tooling.ui)
implementation(projects.tooling.shared)
implementation(projects.tooling.model)
implementation(projects.tooling.database)
implementation(projects.tooling.usecase)
implementation(libs.jewel)
implementation(compose.desktop.currentOs) {
exclude(group = "org.jetbrains.compose.material")
}
}

// FYI: https://youtrack.jetbrains.com/issue/IJPL-1325/Classpath-clash-when-using-coroutines-in-an-unbundled-IntelliJ-plugin
tasks {
run {
// workaround for https://youtrack.jetbrains.com/issue/IDEA-285839/Classpath-clash-when-using-coroutines-in-an-unbundled-IntelliJ-plugin
buildPlugin {
exclude { "kotlinx.coroutines" in it.name }
}
prepareSandbox {
exclude { "kotlinx.coroutines" in it.name }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
package com.kitakkun.backintime.tooling.idea

import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.awt.ComposePanel
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.kitakkun.backintime.tooling.idea.service.BackInTimeDebuggerServiceImpl
import com.kitakkun.backintime.tooling.idea.service.BackInTimeDebuggerSettingsImpl
import com.kitakkun.backintime.tooling.idea.service.PluginStateServiceImpl
import com.kitakkun.backintime.tooling.ui.BackInTimeDebuggerApp
import com.kitakkun.backintime.tooling.ui.BackInTimeTheme
import com.kitakkun.backintime.tooling.ui.compositionlocal.LocalIDENavigator
import com.kitakkun.backintime.tooling.ui.compositionlocal.LocalPluginStateService
import com.kitakkun.backintime.tooling.ui.compositionlocal.LocalServer
import com.kitakkun.backintime.tooling.ui.compositionlocal.LocalSettings

class BackInTimeToolComposePanel {
class BackInTimeToolComposePanel(project: Project) {
val panel = ComposePanel().apply {
setContent {

CompositionLocalProvider(
LocalIDENavigator provides project.service<IDENavigatorImpl>(),
LocalSettings provides BackInTimeDebuggerSettingsImpl.getInstance(),
LocalServer provides BackInTimeDebuggerServiceImpl.getInstance(),
LocalPluginStateService provides PluginStateServiceImpl.getInstance()
) {
BackInTimeTheme {
BackInTimeDebuggerApp()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.intellij.ui.content.ContentFactory
class BackInTimeToolWindowFactory : ToolWindowFactory {
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
val content = ContentFactory.getInstance().createContent(
BackInTimeToolComposePanel().panel, null, false
BackInTimeToolComposePanel(project).panel, null, false
)
toolWindow.contentManager.addContent(content)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.kitakkun.backintime.tooling.idea

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiManager
import com.intellij.psi.util.ClassUtil
import com.kitakkun.backintime.tooling.shared.IDENavigator

@Service(Service.Level.PROJECT)
class IDENavigatorImpl(project: Project) : IDENavigator {
private val psiManager = PsiManager.getInstance(project)

override fun navigateToClass(classFqName: String) {
ApplicationManager.getApplication().executeOnPooledThread {
val psiClass = ReadAction.compute<PsiClass?, Throwable> {
ClassUtil.findPsiClass(psiManager, classFqName)
}
if (psiClass != null) {
ApplicationManager.getApplication().invokeLater {
ReadAction.run<Throwable> {
thisLogger().warn("Navigating to ${psiClass.nameIdentifier}")
psiClass.navigate(true)
}
}
}
}
}
}
Loading

0 comments on commit c05bb12

Please sign in to comment.