fix intellij version (#28)
* idea plugin baseline * selection code send ok * selection code replace ready * clean when plugin upgrade * remove same not necessary
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"dataList":[],
|
||||
"envList":[],
|
||||
"headerList":[],
|
||||
"maxDescriptionLength":-1,
|
||||
"postScript":"",
|
||||
"preScript":"",
|
||||
"projectList":[],
|
||||
"syncModel":{
|
||||
"branch":"master",
|
||||
"domain":"https://github.com",
|
||||
"enabled":false,
|
||||
"namingPolicy":"byDoc",
|
||||
"owner":"",
|
||||
"repo":"",
|
||||
"repoUrl":"",
|
||||
"syncAfterRun":false,
|
||||
"token":"",
|
||||
"type":"github"
|
||||
},
|
||||
"urlEncodedKeyValueList":[],
|
||||
"urlParamsKeyValueList":[],
|
||||
"urlSuffix":""
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"environment":{}
|
||||
}
|
||||
10
packages/gpt-runner-intellij/CHANGELOG.md
Normal file
10
packages/gpt-runner-intellij/CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
||||
<!-- Keep a Changelog guide -> https://keepachangelog.com -->
|
||||
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.0.1] - 2023-06-30
|
||||
|
||||
### Added
|
||||
- Initial project scaffold
|
||||
@@ -9,12 +9,12 @@ fun environment(key: String) = providers.environmentVariable(key)
|
||||
|
||||
plugins {
|
||||
id("java") // Java support
|
||||
alias(libs.plugins.kotlin) // Kotlin support
|
||||
alias(libs.plugins.gradleIntelliJPlugin) // Gradle IntelliJ Plugin
|
||||
alias(libs.plugins.changelog) // Gradle Changelog Plugin
|
||||
alias(libs.plugins.qodana) // Gradle Qodana Plugin
|
||||
alias(libs.plugins.kover) // Gradle Kover Plugin
|
||||
alias(libs.plugins.nodeGradle) // Gradle Node Plugin
|
||||
id("org.jetbrains.kotlin.jvm") version "1.9.0" // Kotlin support
|
||||
id("org.jetbrains.intellij") version "1.15.0" // Gradle IntelliJ Plugin
|
||||
id("org.jetbrains.changelog") version "2.1.2" // Gradle Changelog Plugin
|
||||
id("org.jetbrains.qodana") version "0.1.13" // Gradle Qodana Plugin
|
||||
id("org.jetbrains.kotlinx.kover") version "0.7.3" // Gradle Kover Plugin
|
||||
id("com.github.node-gradle.node") version "7.0.0" // Gradle Node Plugin
|
||||
}
|
||||
|
||||
group = properties("pluginGroup").get()
|
||||
@@ -22,13 +22,17 @@ version = properties("pluginVersion").get()
|
||||
|
||||
// Configure project's dependencies
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://maven.aliyun.com/repository/public")
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
// Dependencies are managed with Gradle version catalog - read more: https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog
|
||||
dependencies {
|
||||
// implementation(libs.annotations)
|
||||
implementation(libs.coroutines)
|
||||
// implementation(libs.coroutines)
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
|
||||
}
|
||||
|
||||
// Set the JVM language level used to build the project. Use Java 11 for 2020.3+, and Java 17 for 2022.2+.
|
||||
@@ -83,8 +87,8 @@ node {
|
||||
// nodeProjectDir.set(File("../gpt-runner-web"))
|
||||
// workDir.set(File("../gpt-runner-web"))
|
||||
|
||||
nodeProjectDir.set(File("./"))
|
||||
workDir.set(File("./"))
|
||||
nodeProjectDir.set(File("../gpt-runner-web"))
|
||||
workDir.set(File("../gpt-runner-web"))
|
||||
}
|
||||
|
||||
val buildGPTRunnerWebClientTask = tasks.register("buildGPTRunnerWebClient", PnpmTask::class) {
|
||||
@@ -94,7 +98,7 @@ val buildGPTRunnerWebClientTask = tasks.register("buildGPTRunnerWebClient", Pnpm
|
||||
|
||||
val runGPTRunnerServerTask = tasks.register("runGPTRunnerServerTask", NodeTask::class) {
|
||||
dependsOn(tasks.pnpmInstall)
|
||||
script.set(File("../gpt-runner-web/dist/start-server.mjs"))
|
||||
script.set(File("../gpt-runner-web/dist/start-server.cjs"))
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
|
||||
@@ -4,7 +4,7 @@ pluginGroup = cn.nicepkg.gptrunner.intellij
|
||||
pluginName = GPT-Runner
|
||||
pluginRepositoryUrl = https://github.com/nicepkg/gpt-runner
|
||||
# SemVer format -> https://semver.org
|
||||
pluginVersion = 0.0.2
|
||||
pluginVersion = 0.0.3
|
||||
|
||||
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
|
||||
pluginSinceBuild = 222
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.nicepkg.gptrunner.intellij
|
||||
|
||||
import com.intellij.DynamicBundle
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
|
||||
@NonNls
|
||||
private const val BUNDLE = "messages.LangBundle"
|
||||
|
||||
object LangBundle : DynamicBundle(BUNDLE) {
|
||||
|
||||
@Suppress("SpreadOperator")
|
||||
@JvmStatic
|
||||
fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) =
|
||||
getMessage(key, *params)
|
||||
|
||||
@Suppress("SpreadOperator", "unused")
|
||||
@JvmStatic
|
||||
fun messagePointer(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) =
|
||||
getLazyMessage(key, *params)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.nicepkg.gptrunner.intellij.actions
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
|
||||
// TODO: impl it
|
||||
class OpenInEditorMode : AnAction() {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
if (e.project == null) return
|
||||
// val project = e.project!!
|
||||
// val gptRunnerService = project.service<IGPTRunnerService>()
|
||||
// project.projectFile
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
e.presentation.isEnabled = e.project != null
|
||||
super.update(e)
|
||||
}
|
||||
|
||||
override fun getActionUpdateThread(): ActionUpdateThread {
|
||||
return ActionUpdateThread.EDT
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners
|
||||
|
||||
/**
|
||||
* 事件名称
|
||||
*/
|
||||
enum class ClientEventName(val value: String) {
|
||||
InitSuccess("initSuccess"),
|
||||
RefreshTree("refreshTree"),
|
||||
RefreshChatTree("refreshChatTree"),
|
||||
RefreshFileTree("refreshFileTree"),
|
||||
InsertCodes("insertCodes"),
|
||||
DiffCodes("diffCodes"),
|
||||
UpdateIdeOpeningFiles("updateIdeOpeningFiles"),
|
||||
UpdateIdeActiveFilePath("updateIdeActiveFilePath"),
|
||||
UpdateUserSelectedText("updateUserSelectedText"),
|
||||
OpenFileInIde("openFileInIde"),
|
||||
OpenFileInFileEditor("openFileInFileEditor"),
|
||||
GoToChatPanel("goToChatPanel")
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.listeners.publish.AppEventPublisher
|
||||
import com.intellij.openapi.editor.event.EditorMouseEvent
|
||||
import com.intellij.openapi.editor.event.EditorMouseListener
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* monitor selected text
|
||||
*/
|
||||
class EditorMouseListenerImpl : EditorMouseListener {
|
||||
|
||||
override fun mouseReleased(event: EditorMouseEvent) {
|
||||
super.mouseReleased(event)
|
||||
val selectedText = event.editor.selectionModel.getSelectedText()
|
||||
val length = selectedText?.trim()?.length
|
||||
if (length != null && length > 0) {
|
||||
// Markdown format
|
||||
val editorImpl = event.editor as EditorImpl
|
||||
val fileExtension = getFileExtension(editorImpl.virtualFile.name)
|
||||
val fullPrompt = getFullPrompt(fileExtension, selectedText)
|
||||
|
||||
// send
|
||||
AppEventPublisher.updateUserSelectedText(fullPrompt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun getFileExtension(filename: String): String {
|
||||
val pattern = Pattern.compile("[^.]+$")
|
||||
val matcher = pattern.matcher(filename)
|
||||
if (matcher.find()) {
|
||||
return matcher.group()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun getFullPrompt(fileExtension: String?, selectedText: String): String {
|
||||
return String.format("\n```%s\n%s\n```", fileExtension, selectedText)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.services.IGPTRunnerExecutableService
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
||||
import com.intellij.ide.plugins.PluginStateListener
|
||||
import com.intellij.openapi.components.service
|
||||
|
||||
class PluginInstallerStateListener : PluginStateListener {
|
||||
override fun install(descriptor: IdeaPluginDescriptor) {
|
||||
service<IGPTRunnerExecutableService>()
|
||||
}
|
||||
|
||||
override fun uninstall(descriptor: IdeaPluginDescriptor) {
|
||||
super.uninstall(descriptor)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.services.IGPTRunnerService
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ProjectManagerListener
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class ProjectStateListener : ProjectManagerListener {
|
||||
override fun projectOpened(project: Project) {
|
||||
thisLogger().debug("project: ${project.name}")
|
||||
thisLogger().debug("project.isInitialized: ${project.isInitialized}")
|
||||
thisLogger().debug("project.isOpen: ${project.isOpen}")
|
||||
thread {
|
||||
runBlocking {
|
||||
project.service<IGPTRunnerService>().startNodeServer()
|
||||
}
|
||||
}
|
||||
super.projectOpened(project)
|
||||
}
|
||||
|
||||
override fun projectClosed(project: Project) {
|
||||
runBlocking { project.service<IGPTRunnerService>().closeNodeServer() }
|
||||
super.projectClosed(project)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners.handler
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.jcef.JBCefJSQuery
|
||||
|
||||
abstract class BaseBrowserEventHandler<T>(val project: Project) : java.util.function.Function<T, JBCefJSQuery.Response> {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners.handler
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.listeners.ClientEventName
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.jcef.JBCefJSQuery
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* handle browser events
|
||||
*/
|
||||
class BrowserEventHandlers(project: Project) : BaseBrowserEventHandler<String>(project) {
|
||||
|
||||
private val handlers: HashMap<String, BaseBrowserEventHandler<JsonElement>> = HashMap()
|
||||
|
||||
@Volatile
|
||||
var initFlag: Boolean = false
|
||||
|
||||
override fun apply(t: String): JBCefJSQuery.Response {
|
||||
if (!initFlag) {
|
||||
synchronized(this) {
|
||||
if (!initFlag) {
|
||||
handlers[ClientEventName.InsertCodes.value] = CodeReplaceHandler(project)
|
||||
}
|
||||
initFlag = true
|
||||
}
|
||||
}
|
||||
|
||||
val gson = Gson()
|
||||
val any = gson.fromJson(t, Any::class.java)
|
||||
if (any is JsonArray) {
|
||||
val eventName = any.get(0)
|
||||
if (handlers.contains(eventName.asString)){
|
||||
return handlers.get(eventName.asString)!!.apply(any.get(1))
|
||||
}
|
||||
}
|
||||
|
||||
return JBCefJSQuery.Response("Done")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners.handler
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.jcef.JBCefJSQuery
|
||||
|
||||
/**
|
||||
* TODO 验证
|
||||
*
|
||||
* @author shield
|
||||
*/
|
||||
class CodeReplaceHandler(project: Project) : BaseBrowserEventHandler<JsonElement>(project) {
|
||||
|
||||
override fun apply(t: JsonElement): JBCefJSQuery.Response {
|
||||
val editor = FileEditorManager.getInstance(project).getSelectedTextEditor()
|
||||
if (editor != null) {
|
||||
val selectionModel = editor.selectionModel
|
||||
|
||||
if (t is JsonObject && t.has("codes")) {
|
||||
val content = t.get("codes").asString
|
||||
editor.document.replaceString(selectionModel.selectionStart, selectionModel.selectionEnd, content)
|
||||
}
|
||||
}
|
||||
|
||||
return JBCefJSQuery.Response("Done")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners.publish
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.listeners.ClientEventName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
@Serializable
|
||||
class AppEvent(value: String?, eventData: Any?, type: String?) {
|
||||
|
||||
private val eventName: String? = null
|
||||
private val type: String? = null
|
||||
private val eventData: Any? = null
|
||||
|
||||
|
||||
private var text: String? = null
|
||||
private val codes: String? = null
|
||||
|
||||
companion object {
|
||||
fun of(eventName: ClientEventName, eventData: Any, type: String): AppEvent {
|
||||
return AppEvent(eventName.value, eventData, type)
|
||||
}
|
||||
|
||||
fun of(text: String): AppEvent {
|
||||
val event = AppEvent()
|
||||
event.text = text
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
constructor() : this(null, null, null)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.nicepkg.gptrunner.intellij.listeners.publish
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.listeners.ClientEventName
|
||||
import cn.nicepkg.gptrunner.intellij.ui.windows.GPTRunnerWindowHolder
|
||||
import com.google.gson.JsonObject
|
||||
|
||||
/**
|
||||
* push event to web
|
||||
*/
|
||||
class AppEventPublisher {
|
||||
|
||||
companion object {
|
||||
|
||||
|
||||
fun updateUserSelectedText(text: String) {
|
||||
val jsonObject = JsonObject()
|
||||
jsonObject.addProperty("text", text)
|
||||
|
||||
publish(ClientEventName.UpdateUserSelectedText.value, jsonObject)
|
||||
}
|
||||
|
||||
|
||||
private fun publish(eventName: String, eventData: JsonObject) {
|
||||
GPTRunnerWindowHolder.jBCefBrowser!!.cefBrowser.executeJavaScript(
|
||||
"window.__emitter__.emit( \"${eventName}\", $eventData )",
|
||||
null,
|
||||
0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.nicepkg.gptrunner.intellij.services
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
|
||||
abstract class AbstractService {
|
||||
val pluginId = "cn.nicepkg.gptrunner.intellij"
|
||||
val plugin = PluginManagerCore.getPlugin(PluginId.getId(pluginId))!!
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.nicepkg.gptrunner.intellij.services
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
interface IGPTRunnerExecutableService {
|
||||
val userHome: Path
|
||||
val gptRunnerExecutablesDir: Path
|
||||
val gptRunnerExecutableDir: Path
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.nicepkg.gptrunner.intellij.services
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.apache.commons.lang3.SystemUtils
|
||||
|
||||
interface IGPTRunnerService : Disposable {
|
||||
val port: Int
|
||||
suspend fun startNodeServer()
|
||||
suspend fun closeNodeServer()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.nicepkg.gptrunner.intellij.services
|
||||
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
object RunnerAgentCommandLine {
|
||||
private val LOG = Logger.getInstance(RunnerAgentCommandLine::class.java)
|
||||
|
||||
fun getNodeExecutablePath(): Path? {
|
||||
val path = PathEnvironmentVariableUtil.findExecutableInPathOnAnyOS("node")
|
||||
if (path == null) {
|
||||
LOG.debug("在 PATH 中找不到 node 可执行文件")
|
||||
return null
|
||||
}
|
||||
val nioPath = path.toPath()
|
||||
if (SystemInfoRt.isUnix && !Files.isExecutable(nioPath)) {
|
||||
LOG.warn("node 可执行文件没有执行权限: $nioPath")
|
||||
return null
|
||||
}
|
||||
LOG.debug("在 $nioPath 找到了 node 可执行文件")
|
||||
return nioPath
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,17 +2,18 @@ package cn.nicepkg.gptrunner.intellij.services.impl
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.services.AbstractService
|
||||
import cn.nicepkg.gptrunner.intellij.services.IGPTRunnerExecutableService
|
||||
import com.intellij.openapi.util.io.NioFiles
|
||||
import org.apache.commons.lang3.SystemUtils
|
||||
import java.io.File
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.nio.file.attribute.FileAttribute
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import kotlin.io.path.*
|
||||
import kotlin.reflect.jvm.internal.impl.builtins.StandardNames.FqNames.target
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.notExists
|
||||
|
||||
|
||||
class GPTRunnerExecutableService : AbstractService(),
|
||||
@@ -21,8 +22,14 @@ class GPTRunnerExecutableService : AbstractService(),
|
||||
override val gptRunnerExecutablesDir = userHome.resolve(".gpt-runner")
|
||||
override val gptRunnerExecutableDir = gptRunnerExecutablesDir.resolve("GPT-Runner-${plugin.version}")
|
||||
|
||||
init {
|
||||
init {
|
||||
if (gptRunnerExecutableDir.notExists()) {
|
||||
if (gptRunnerExecutablesDir.exists()) {
|
||||
// clean
|
||||
NioFiles.deleteRecursively(gptRunnerExecutablesDir)
|
||||
}
|
||||
|
||||
// install
|
||||
gptRunnerExecutableDir.createDirectories()
|
||||
unzipGPTRunnerExecutable()
|
||||
} else if (gptRunnerExecutableDir.listDirectoryEntries().isEmpty()) {
|
||||
|
||||
@@ -3,6 +3,8 @@ package cn.nicepkg.gptrunner.intellij.services.impl
|
||||
import cn.nicepkg.gptrunner.intellij.services.AbstractService
|
||||
import cn.nicepkg.gptrunner.intellij.services.IGPTRunnerExecutableService
|
||||
import cn.nicepkg.gptrunner.intellij.services.IGPTRunnerService
|
||||
import cn.nicepkg.gptrunner.intellij.services.RunnerAgentCommandLine
|
||||
import cn.nicepkg.gptrunner.intellij.utils.RunnerAgentUtil
|
||||
import com.intellij.codeInsight.hint.HintManager
|
||||
import com.intellij.ide.DataManager
|
||||
import com.intellij.notification.NotificationDisplayType
|
||||
@@ -17,6 +19,8 @@ import kotlinx.coroutines.*
|
||||
import java.io.File
|
||||
import kotlin.concurrent.thread
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.util.io.exists
|
||||
import kotlin.io.path.isExecutable
|
||||
|
||||
|
||||
// TODO: 需要提供几个action去启动/停止server
|
||||
@@ -62,7 +66,8 @@ class GPTRunnerService(project: Project) : AbstractService(),
|
||||
port.toString(),
|
||||
"--client-dist-path",
|
||||
"browser"
|
||||
).directory(executableService.gptRunnerExecutableDir.toFile()) // Update this line
|
||||
).directory(executableService.gptRunnerExecutableDir.toFile().resolve("dist"))
|
||||
// Update this line
|
||||
.start()
|
||||
// val serverExecutablePath = executableService.gptRunnerExecutableDir.toFile().path+"/server-executable";
|
||||
// process = ProcessBuilder(
|
||||
@@ -123,6 +128,13 @@ class GPTRunnerService(project: Project) : AbstractService(),
|
||||
|
||||
|
||||
fun getMyNodePath(): String {
|
||||
// 优先查找系统环境变量 - node
|
||||
val nodeExecutablePath = RunnerAgentCommandLine.getNodeExecutablePath()
|
||||
if (nodeExecutablePath != null && nodeExecutablePath.exists() && nodeExecutablePath.isExecutable()){
|
||||
return nodeExecutablePath.toString();
|
||||
}
|
||||
|
||||
// 其他
|
||||
val osName = System.getProperty("os.name").toLowerCase()
|
||||
if (osName.contains("mac") || osName.contains("nix") || osName.contains("nux")) {
|
||||
val nodePath = getNodePath()
|
||||
|
||||
@@ -2,25 +2,15 @@ package cn.nicepkg.gptrunner.intellij.ui.windows
|
||||
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.services.IGPTRunnerService
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.ide.ui.LafManager
|
||||
import com.intellij.ide.ui.LafManagerListener
|
||||
import com.intellij.ide.ui.laf.UIThemeBasedLookAndFeelInfo
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.jcef.JBCefBrowser
|
||||
import com.intellij.ui.jcef.JBCefBrowserBuilder
|
||||
import com.intellij.ui.jcef.JBCefClient
|
||||
import com.intellij.ui.jcef.executeJavaScriptAsync
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import javax.swing.JComponent
|
||||
|
||||
class GPTRunnerWindow(project: Project, disposable: Disposable) {
|
||||
private val jBCefBrowser =
|
||||
@@ -29,15 +19,21 @@ class GPTRunnerWindow(project: Project, disposable: Disposable) {
|
||||
|
||||
init {
|
||||
println("init windows")
|
||||
println("project.basePath="+project.basePath)
|
||||
ApplicationManager.getApplication().messageBus.connect(disposable)
|
||||
println("project.basePath=" + project.basePath)
|
||||
val messageBusConnection = ApplicationManager.getApplication().messageBus.connect(disposable)
|
||||
messageBusConnection
|
||||
.subscribe(LafManagerListener.TOPIC, LafManagerListener {
|
||||
val isDark =
|
||||
(it.currentLookAndFeel as UIThemeBasedLookAndFeelInfo).theme.isDark
|
||||
jBCefBrowser.executeJavaScriptAsync("document.body.dataset.theme = `${if (isDark) "jetbrainsDark" else "jetbrainsLight"}`")
|
||||
})
|
||||
// window.setAdditionalGearActions();
|
||||
|
||||
// window.setAdditionalGearActions()
|
||||
// jBCefBrowser.jbCefClient.setProperty(JBCefClient.Properties.JS_QUERY_POOL_SIZE, 3)
|
||||
|
||||
}
|
||||
|
||||
fun getContent() = jBCefBrowser.component
|
||||
|
||||
fun getBrowser() = jBCefBrowser
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package cn.nicepkg.gptrunner.intellij.ui.windows
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.listeners.ClientEventName
|
||||
import cn.nicepkg.gptrunner.intellij.listeners.handler.BrowserEventHandlers
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.wm.ToolWindow
|
||||
import com.intellij.openapi.wm.ToolWindowFactory
|
||||
import com.intellij.ui.content.ContentFactory
|
||||
import com.intellij.ui.jcef.JBCefBrowserBase
|
||||
import com.intellij.ui.jcef.JBCefJSQuery
|
||||
import org.cef.browser.CefBrowser
|
||||
import org.cef.browser.CefFrame
|
||||
import org.cef.handler.CefLoadHandler
|
||||
import org.cef.network.CefRequest
|
||||
|
||||
class GPTRunnerWindowFactory : ToolWindowFactory {
|
||||
|
||||
init {
|
||||
thisLogger().info("GPTRunnerWindowFactory init.")
|
||||
}
|
||||
|
||||
override fun createToolWindowContent(project: Project, window: ToolWindow) {
|
||||
val gptRunnerWindow = GPTRunnerWindow(project, window.disposable)
|
||||
val content = ContentFactory.getInstance().createContent(
|
||||
gptRunnerWindow.getContent(), null, true
|
||||
)
|
||||
window.contentManager.addContent(content)
|
||||
val jbCefBrowser = gptRunnerWindow.getBrowser()
|
||||
val jsQuery = JBCefJSQuery.create(jbCefBrowser as JBCefBrowserBase)
|
||||
|
||||
jsQuery.addHandler { t ->
|
||||
println("监听js传参 $t")
|
||||
|
||||
BrowserEventHandlers(project).apply(t)
|
||||
}
|
||||
|
||||
|
||||
jbCefBrowser.jbCefClient.addLoadHandler(object : CefLoadHandler {
|
||||
override fun onLoadingStateChange(browser: CefBrowser?, isLoading: Boolean, canGoBack: Boolean, canGoForward: Boolean) {
|
||||
}
|
||||
|
||||
override fun onLoadStart(browser: CefBrowser?, frame: CefFrame?, transitionType: CefRequest.TransitionType?) {
|
||||
}
|
||||
|
||||
override fun onLoadEnd(browser: CefBrowser?, frame: CefFrame?, httpStatusCode: Int) {
|
||||
println("onLoadEnd" + frame?.url)
|
||||
|
||||
browser?.executeJavaScript(
|
||||
"window.addEventListener('message', event => {\n" +
|
||||
"const message = event.data || {};\n" +
|
||||
"console.log(event)\n" +
|
||||
"const {eventName, eventData} = message\n" +
|
||||
"const strEvent = JSON.stringify(message) \n" +
|
||||
// jsQuery.inject("strEvent") +
|
||||
"window.__emitter__.emit(eventName, eventData, \"ReceiveMessage\")" +
|
||||
" })",
|
||||
null,
|
||||
0
|
||||
)
|
||||
|
||||
browser?.executeJavaScript(
|
||||
"oldEmit = window.__emitter__.emit\n" +
|
||||
" window.__emitter__.emit = function (...args) {\n" +
|
||||
" const [eventName, eventData, type] = args\n" +
|
||||
" if (type !== \"ReceiveMessage\") {\n" +
|
||||
" const strEvent = JSON.stringify(args) \n" +
|
||||
jsQuery.inject("strEvent") +
|
||||
" }\n" +
|
||||
" return oldEmit.apply(this, args)\n" +
|
||||
" }",
|
||||
null,
|
||||
1
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
override fun onLoadError(browser: CefBrowser?, frame: CefFrame?, errorCode: CefLoadHandler.ErrorCode?, errorText: String?, failedUrl: String?) {
|
||||
}
|
||||
|
||||
}, gptRunnerWindow.getBrowser().cefBrowser)
|
||||
|
||||
GPTRunnerWindowHolder.jBCefBrowser = jbCefBrowser
|
||||
GPTRunnerWindowHolder.jsQuery = jsQuery
|
||||
}
|
||||
|
||||
override fun shouldBeAvailable(project: Project) = true
|
||||
|
||||
override fun init(toolWindow: ToolWindow) {
|
||||
super.init(toolWindow)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package cn.nicepkg.gptrunner.intellij.ui.windows
|
||||
|
||||
import com.intellij.ui.jcef.JBCefBrowser
|
||||
import com.intellij.ui.jcef.JBCefJSQuery
|
||||
|
||||
class GPTRunnerWindowHolder {
|
||||
|
||||
companion object {
|
||||
var jsQuery: JBCefJSQuery? = null
|
||||
var jBCefBrowser: JBCefBrowser? = null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package cn.nicepkg.gptrunner.intellij.utils
|
||||
|
||||
import cn.nicepkg.gptrunner.intellij.services.IGPTRunnerExecutableService
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import java.nio.file.Path
|
||||
|
||||
object RunnerAgentUtil {
|
||||
|
||||
|
||||
fun agentDirectoryPath(): Path {
|
||||
val executableService = ApplicationManager.getApplication().getService(IGPTRunnerExecutableService::class.java)
|
||||
return executableService.gptRunnerExecutableDir.resolve("dist")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,4 +39,10 @@
|
||||
<action id="cn.nicepkg.gptrunner.intellij.actions.OpenInEditorMode" class="cn.nicepkg.gptrunner.intellij.actions.OpenInEditorMode">
|
||||
</action>
|
||||
</actions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<editorFactoryMouseListener
|
||||
implementation="cn.nicepkg.gptrunner.intellij.listeners.EditorMouseListenerImpl"/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
name=GPT-Runner Intellij
|
||||
|
||||
messages.openGPTRunnerInEditorMode=Open GPT-Runner in Editor Mode.
|
||||
|
||||
action.cn.nicepkg.gptrunner.intellij.actions.OpenInEditorMode.text=Open GPT-Runner in Editor Mode.
|
||||
|
||||
Reference in New Issue
Block a user