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:
shield
2023-08-28 10:56:55 +08:00
committed by GitHub
parent 612c76d33e
commit 4e665f7bf8
28 changed files with 578 additions and 31 deletions

View File

@@ -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":""
}

View File

@@ -0,0 +1,3 @@
{
"environment":{}
}

View File

@@ -0,0 +1,10 @@
<!-- Keep a Changelog guide -> https://keepachangelog.com -->
# Changelog
## [Unreleased]
## [0.0.1] - 2023-06-30
### Added
- Initial project scaffold

View File

@@ -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 {

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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> {
}

View File

@@ -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")
}
}

View File

@@ -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")
}
}

View File

@@ -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)
}

View File

@@ -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
)
}
}
}

View File

@@ -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))!!
}

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -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
}
}

View File

@@ -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()) {

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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")
}
}

View File

@@ -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>

View File

@@ -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.