Skip to content

Commit c707900

Browse files
CopilotMte90
andauthored
Add status bar click handler and centralized project settings for backend configuration (#24)
Co-authored-by: Mte90 <403283+Mte90@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent 3294ecd commit c707900

File tree

6 files changed

+154
-29
lines changed

6 files changed

+154
-29
lines changed

ide-plugins/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ tasks {
4141
}
4242

4343
patchPluginXml {
44-
version.set(project.version.toString())
44+
sinceBuild.set("231")
45+
untilBuild.set("241.*")
4546
}
4647
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.picocode
2+
3+
import com.intellij.openapi.options.Configurable
4+
import com.intellij.openapi.project.Project
5+
import com.intellij.ui.components.JBLabel
6+
import com.intellij.ui.components.JBTextField
7+
import com.intellij.util.ui.FormBuilder
8+
import javax.swing.JComponent
9+
import javax.swing.JPanel
10+
11+
/**
12+
* Project settings configurable for PicoCode plugin
13+
* Provides UI to configure backend server host and port
14+
*/
15+
class PicoCodeConfigurable(private val project: Project) : Configurable {
16+
17+
private val hostField = JBTextField(20)
18+
private val portField = JBTextField(10)
19+
private var settingsPanel: JPanel? = null
20+
21+
override fun getDisplayName(): String = "PicoCode"
22+
23+
override fun createComponent(): JComponent {
24+
val settings = PicoCodeSettings.getInstance(project)
25+
val state = settings.state
26+
27+
// Initialize fields with current settings
28+
hostField.text = state.serverHost
29+
portField.text = state.serverPort.toString()
30+
31+
// Create the settings panel with form layout
32+
settingsPanel = FormBuilder.createFormBuilder()
33+
.addLabeledComponent(JBLabel("Backend Host:"), hostField, 1, false)
34+
.addLabeledComponent(JBLabel("Backend Port:"), portField, 1, false)
35+
.addComponentFillVertically(JPanel(), 0)
36+
.panel
37+
38+
return settingsPanel!!
39+
}
40+
41+
override fun isModified(): Boolean {
42+
val settings = PicoCodeSettings.getInstance(project)
43+
val state = settings.state
44+
45+
val hostModified = hostField.text != state.serverHost
46+
val portModified = portField.text.toIntOrNull() != state.serverPort
47+
48+
return hostModified || portModified
49+
}
50+
51+
override fun apply() {
52+
val settings = PicoCodeSettings.getInstance(project)
53+
val state = settings.state
54+
55+
state.serverHost = hostField.text.trim().ifEmpty { "localhost" }
56+
state.serverPort = portField.text.trim().toIntOrNull() ?: 8000
57+
58+
settings.loadState(state)
59+
}
60+
61+
override fun reset() {
62+
val settings = PicoCodeSettings.getInstance(project)
63+
val state = settings.state
64+
65+
hostField.text = state.serverHost
66+
portField.text = state.serverPort.toString()
67+
}
68+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.picocode
2+
3+
import com.intellij.openapi.components.PersistentStateComponent
4+
import com.intellij.openapi.components.State
5+
import com.intellij.openapi.components.Storage
6+
import com.intellij.openapi.components.Service
7+
import com.intellij.openapi.project.Project
8+
import com.intellij.util.xmlb.XmlSerializerUtil
9+
10+
/**
11+
* Project-level settings for PicoCode plugin
12+
* Stores backend server host and port configuration
13+
*/
14+
@State(
15+
name = "PicoCodeSettings",
16+
storages = [Storage("picocode.xml")]
17+
)
18+
@Service(Service.Level.PROJECT)
19+
class PicoCodeSettings : PersistentStateComponent<PicoCodeSettings.SettingsState> {
20+
21+
data class SettingsState(
22+
var serverHost: String = "localhost",
23+
var serverPort: Int = 8000
24+
)
25+
26+
private var state = SettingsState()
27+
28+
override fun getState(): SettingsState = state
29+
30+
override fun loadState(state: SettingsState) {
31+
XmlSerializerUtil.copyBean(state, this.state)
32+
}
33+
34+
companion object {
35+
fun getInstance(project: Project): PicoCodeSettings {
36+
return project.getService(PicoCodeSettings::class.java)
37+
}
38+
}
39+
}

ide-plugins/src/main/kotlin/com/picocode/PicoCodeStatusBarWidget.kt

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import com.intellij.openapi.project.Project
55
import com.intellij.openapi.wm.StatusBar
66
import com.intellij.openapi.wm.StatusBarWidget
77
import com.intellij.openapi.wm.StatusBarWidgetFactory
8+
import com.intellij.openapi.wm.ToolWindowManager
9+
import com.intellij.openapi.ui.Messages
810
import com.intellij.util.Consumer
911
import com.google.gson.Gson
1012
import com.google.gson.JsonObject
@@ -22,8 +24,6 @@ class PicoCodeStatusBarWidget(private val project: Project) : StatusBarWidget,
2224

2325
companion object {
2426
const val ID = "PicoCodeStatusWidget"
25-
private const val DEFAULT_HOST = "localhost"
26-
private const val DEFAULT_PORT = 8000
2727
private const val POLLING_INTERVAL_SECONDS = 5L
2828
}
2929

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

9494
override fun getClickConsumer(): Consumer<MouseEvent>? {
9595
return Consumer {
96-
// Optional: could open tool window or trigger re-indexing
96+
// Open the PicoCode RAG tool window on click
97+
ApplicationManager.getApplication().invokeLater {
98+
val toolWindowManager = ToolWindowManager.getInstance(project)
99+
val toolWindow = toolWindowManager.getToolWindow("PicoCode RAG")
100+
101+
if (toolWindow != null) {
102+
toolWindow.show()
103+
} else {
104+
Messages.showInfoMessage(
105+
project,
106+
"PicoCode RAG tool window is not available. Please ensure the plugin is properly installed.",
107+
"PicoCode RAG"
108+
)
109+
}
110+
}
97111
}
98112
}
99113

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

128142
private fun getOrCreateProject(projectPath: String): String? {
129143
return try {
130-
val url = URL("http://$DEFAULT_HOST:$DEFAULT_PORT/api/projects")
144+
val settings = PicoCodeSettings.getInstance(project)
145+
val host = settings.state.serverHost
146+
val port = settings.state.serverPort
147+
148+
val url = URL("http://$host:$port/api/projects")
131149
val connection = url.openConnection() as HttpURLConnection
132150
connection.requestMethod = "POST"
133151
connection.setRequestProperty("Content-Type", "application/json")
@@ -149,7 +167,11 @@ class PicoCodeStatusBarWidget(private val project: Project) : StatusBarWidget,
149167

150168
private fun fetchProjectStatus(projectId: String): Pair<String, IndexingStats?> {
151169
return try {
152-
val url = URL("http://$DEFAULT_HOST:$DEFAULT_PORT/api/projects/$projectId")
170+
val settings = PicoCodeSettings.getInstance(project)
171+
val host = settings.state.serverHost
172+
val port = settings.state.serverPort
173+
174+
val url = URL("http://$host:$port/api/projects/$projectId")
153175
val connection = url.openConnection() as HttpURLConnection
154176
connection.requestMethod = "GET"
155177

ide-plugins/src/main/kotlin/com/picocode/PicoCodeToolWindowContent.kt

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
package com.picocode
22

33
import com.intellij.openapi.application.ApplicationManager
4-
import com.intellij.openapi.fileEditor.FileEditorManager
5-
import com.intellij.openapi.fileEditor.OpenFileDescriptor
64
import com.intellij.openapi.project.Project
7-
import com.intellij.openapi.vfs.LocalFileSystem
85
import com.intellij.ui.components.JBScrollPane
96
import com.intellij.ui.components.JBTextArea
10-
import com.intellij.ui.components.JBTextField
11-
import com.intellij.util.ui.FormBuilder
127
import java.awt.BorderLayout
13-
import java.io.File
148
import javax.swing.*
159
import java.net.HttpURLConnection
1610
import java.net.URL
@@ -23,10 +17,6 @@ import com.google.gson.JsonObject
2317
* Assumes PicoCode server is already running
2418
*/
2519
class PicoCodeToolWindowContent(private val project: Project) {
26-
// PicoCode server configuration (only host and port needed)
27-
private val serverHostField = JBTextField("localhost")
28-
private val serverPortField = JBTextField("8000")
29-
3020
// Chat components
3121
private val chatArea = JBTextArea(25, 60)
3222
private val inputField = JBTextArea(3, 60)
@@ -42,26 +32,26 @@ class PicoCodeToolWindowContent(private val project: Project) {
4232
inputField.wrapStyleWord = true
4333
}
4434

45-
private fun getServerHost(): String = serverHostField.text.trim().ifEmpty { "localhost" }
46-
private fun getServerPort(): Int = serverPortField.text.trim().toIntOrNull() ?: 8000
35+
private fun getServerHost(): String {
36+
val settings = PicoCodeSettings.getInstance(project)
37+
return settings.state.serverHost
38+
}
39+
40+
private fun getServerPort(): Int {
41+
val settings = PicoCodeSettings.getInstance(project)
42+
return settings.state.serverPort
43+
}
4744

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

51-
// Server config panel with re-index button
52-
val configPanel = FormBuilder.createFormBuilder()
53-
.addLabeledComponent("PicoCode Host:", serverHostField)
54-
.addLabeledComponent("PicoCode Port:", serverPortField)
55-
.panel
56-
57-
// Add a re-index button to config panel
48+
// Add a re-index button at the top
5849
val reindexBtn = JButton("Re-index Project")
5950
reindexBtn.addActionListener {
6051
reindexProject()
6152
}
62-
val configPanelWithButton = JPanel(BorderLayout())
63-
configPanelWithButton.add(configPanel, BorderLayout.CENTER)
64-
configPanelWithButton.add(reindexBtn, BorderLayout.SOUTH)
53+
val topPanel = JPanel(BorderLayout())
54+
topPanel.add(reindexBtn, BorderLayout.EAST)
6555

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

10191
// Layout
102-
panel.add(configPanelWithButton, BorderLayout.NORTH)
92+
panel.add(topPanel, BorderLayout.NORTH)
10393
panel.add(chatScrollPane, BorderLayout.CENTER)
10494
panel.add(inputPanel, BorderLayout.SOUTH)
10595

ide-plugins/src/main/resources/META-INF/plugin.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,10 @@
1818
factoryClass="com.picocode.PicoCodeToolWindowFactory"/>
1919
<statusBarWidgetFactory implementation="com.picocode.PicoCodeStatusBarWidgetFactory"
2020
order="after memoryIndicator"/>
21+
<projectConfigurable parentId="tools"
22+
instance="com.picocode.PicoCodeConfigurable"
23+
id="com.picocode.PicoCodeConfigurable"
24+
displayName="PicoCode"/>
25+
<projectService serviceImplementation="com.picocode.PicoCodeSettings"/>
2126
</extensions>
2227
</idea-plugin>

0 commit comments

Comments
 (0)