Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion ide-plugins/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ tasks {
}

patchPluginXml {
version.set(project.version.toString())
sinceBuild.set("231")
untilBuild.set("241.*")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot the latest version is 252

}
}
68 changes: 68 additions & 0 deletions ide-plugins/src/main/kotlin/com/picocode/PicoCodeConfigurable.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.picocode

import com.intellij.openapi.options.Configurable
import com.intellij.openapi.project.Project
import com.intellij.ui.components.JBLabel
import com.intellij.ui.components.JBTextField
import com.intellij.util.ui.FormBuilder
import javax.swing.JComponent
import javax.swing.JPanel

/**
* Project settings configurable for PicoCode plugin
* Provides UI to configure backend server host and port
*/
class PicoCodeConfigurable(private val project: Project) : Configurable {

private val hostField = JBTextField(20)
private val portField = JBTextField(10)
private var settingsPanel: JPanel? = null

override fun getDisplayName(): String = "PicoCode"

override fun createComponent(): JComponent {
val settings = PicoCodeSettings.getInstance(project)
val state = settings.state

// Initialize fields with current settings
hostField.text = state.serverHost
portField.text = state.serverPort.toString()

// Create the settings panel with form layout
settingsPanel = FormBuilder.createFormBuilder()
.addLabeledComponent(JBLabel("Backend Host:"), hostField, 1, false)
.addLabeledComponent(JBLabel("Backend Port:"), portField, 1, false)
.addComponentFillVertically(JPanel(), 0)
.panel

return settingsPanel!!
}

override fun isModified(): Boolean {
val settings = PicoCodeSettings.getInstance(project)
val state = settings.state

val hostModified = hostField.text != state.serverHost
val portModified = portField.text.toIntOrNull() != state.serverPort

return hostModified || portModified
}

override fun apply() {
val settings = PicoCodeSettings.getInstance(project)
val state = settings.state

state.serverHost = hostField.text.trim().ifEmpty { "localhost" }
state.serverPort = portField.text.trim().toIntOrNull() ?: 8000

settings.loadState(state)
}

override fun reset() {
val settings = PicoCodeSettings.getInstance(project)
val state = settings.state

hostField.text = state.serverHost
portField.text = state.serverPort.toString()
}
}
39 changes: 39 additions & 0 deletions ide-plugins/src/main/kotlin/com/picocode/PicoCodeSettings.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.picocode

import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
import com.intellij.util.xmlb.XmlSerializerUtil

/**
* Project-level settings for PicoCode plugin
* Stores backend server host and port configuration
*/
@State(
name = "PicoCodeSettings",
storages = [Storage("picocode.xml")]
)
@Service(Service.Level.PROJECT)
class PicoCodeSettings : PersistentStateComponent<PicoCodeSettings.SettingsState> {

data class SettingsState(
var serverHost: String = "localhost",
var serverPort: Int = 8000
)

private var state = SettingsState()

override fun getState(): SettingsState = state

override fun loadState(state: SettingsState) {
XmlSerializerUtil.copyBean(state, this.state)
}

companion object {
fun getInstance(project: Project): PicoCodeSettings {
return project.getService(PicoCodeSettings::class.java)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.StatusBar
import com.intellij.openapi.wm.StatusBarWidget
import com.intellij.openapi.wm.StatusBarWidgetFactory
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.openapi.ui.Messages
import com.intellij.util.Consumer
import com.google.gson.Gson
import com.google.gson.JsonObject
Expand All @@ -22,8 +24,6 @@ class PicoCodeStatusBarWidget(private val project: Project) : StatusBarWidget,

companion object {
const val ID = "PicoCodeStatusWidget"
private const val DEFAULT_HOST = "localhost"
private const val DEFAULT_PORT = 8000
private const val POLLING_INTERVAL_SECONDS = 5L
}

Expand Down Expand Up @@ -93,7 +93,21 @@ class PicoCodeStatusBarWidget(private val project: Project) : StatusBarWidget,

override fun getClickConsumer(): Consumer<MouseEvent>? {
return Consumer {
// Optional: could open tool window or trigger re-indexing
// Open the PicoCode RAG tool window on click
ApplicationManager.getApplication().invokeLater {
val toolWindowManager = ToolWindowManager.getInstance(project)
val toolWindow = toolWindowManager.getToolWindow("PicoCode RAG")

if (toolWindow != null) {
toolWindow.show()
} else {
Messages.showInfoMessage(
project,
"PicoCode RAG tool window is not available. Please ensure the plugin is properly installed.",
"PicoCode RAG"
)
}
}
}
}

Expand Down Expand Up @@ -127,7 +141,11 @@ class PicoCodeStatusBarWidget(private val project: Project) : StatusBarWidget,

private fun getOrCreateProject(projectPath: String): String? {
return try {
val url = URL("http://$DEFAULT_HOST:$DEFAULT_PORT/api/projects")
val settings = PicoCodeSettings.getInstance(project)
val host = settings.state.serverHost
val port = settings.state.serverPort

val url = URL("http://$host:$port/api/projects")
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("Content-Type", "application/json")
Expand All @@ -149,7 +167,11 @@ class PicoCodeStatusBarWidget(private val project: Project) : StatusBarWidget,

private fun fetchProjectStatus(projectId: String): Pair<String, IndexingStats?> {
return try {
val url = URL("http://$DEFAULT_HOST:$DEFAULT_PORT/api/projects/$projectId")
val settings = PicoCodeSettings.getInstance(project)
val host = settings.state.serverHost
val port = settings.state.serverPort

val url = URL("http://$host:$port/api/projects/$projectId")
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
package com.picocode

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.ui.components.JBScrollPane
import com.intellij.ui.components.JBTextArea
import com.intellij.ui.components.JBTextField
import com.intellij.util.ui.FormBuilder
import java.awt.BorderLayout
import java.io.File
import javax.swing.*
import java.net.HttpURLConnection
import java.net.URL
Expand All @@ -23,10 +17,6 @@ import com.google.gson.JsonObject
* Assumes PicoCode server is already running
*/
class PicoCodeToolWindowContent(private val project: Project) {
// PicoCode server configuration (only host and port needed)
private val serverHostField = JBTextField("localhost")
private val serverPortField = JBTextField("8000")

// Chat components
private val chatArea = JBTextArea(25, 60)
private val inputField = JBTextArea(3, 60)
Expand All @@ -42,26 +32,26 @@ class PicoCodeToolWindowContent(private val project: Project) {
inputField.wrapStyleWord = true
}

private fun getServerHost(): String = serverHostField.text.trim().ifEmpty { "localhost" }
private fun getServerPort(): Int = serverPortField.text.trim().toIntOrNull() ?: 8000
private fun getServerHost(): String {
val settings = PicoCodeSettings.getInstance(project)
return settings.state.serverHost
}

private fun getServerPort(): Int {
val settings = PicoCodeSettings.getInstance(project)
return settings.state.serverPort
}

fun getContent(): JComponent {
val panel = JPanel(BorderLayout())

// Server config panel with re-index button
val configPanel = FormBuilder.createFormBuilder()
.addLabeledComponent("PicoCode Host:", serverHostField)
.addLabeledComponent("PicoCode Port:", serverPortField)
.panel

// Add a re-index button to config panel
// Add a re-index button at the top
val reindexBtn = JButton("Re-index Project")
reindexBtn.addActionListener {
reindexProject()
}
val configPanelWithButton = JPanel(BorderLayout())
configPanelWithButton.add(configPanel, BorderLayout.CENTER)
configPanelWithButton.add(reindexBtn, BorderLayout.SOUTH)
val topPanel = JPanel(BorderLayout())
topPanel.add(reindexBtn, BorderLayout.EAST)

// Chat display area
val chatScrollPane = JBScrollPane(chatArea)
Expand Down Expand Up @@ -99,7 +89,7 @@ class PicoCodeToolWindowContent(private val project: Project) {
inputPanel.add(buttonPanel, BorderLayout.SOUTH)

// Layout
panel.add(configPanelWithButton, BorderLayout.NORTH)
panel.add(topPanel, BorderLayout.NORTH)
panel.add(chatScrollPane, BorderLayout.CENTER)
panel.add(inputPanel, BorderLayout.SOUTH)

Expand Down
5 changes: 5 additions & 0 deletions ide-plugins/src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,10 @@
factoryClass="com.picocode.PicoCodeToolWindowFactory"/>
<statusBarWidgetFactory implementation="com.picocode.PicoCodeStatusBarWidgetFactory"
order="after memoryIndicator"/>
<projectConfigurable parentId="tools"
instance="com.picocode.PicoCodeConfigurable"
id="com.picocode.PicoCodeConfigurable"
displayName="PicoCode"/>
<projectService serviceImplementation="com.picocode.PicoCodeSettings"/>
</extensions>
</idea-plugin>