Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 12, 2025

Adds clickable status bar widget to open the chat window and centralizes backend host/port configuration in PyCharm project settings.

Changes

Status Bar Click Handler

  • PicoCodeStatusBarWidget.kt: Implemented getClickConsumer() to open "PicoCode RAG" tool window via ToolWindowManager, with EDT-compliant invocation

Centralized Settings Service

  • PicoCodeSettings.kt (new): Project-level PersistentStateComponent storing host/port in .idea/picocode.xml, defaults to localhost:8000
  • PicoCodeConfigurable.kt (new): Settings UI under Tools > PicoCode with host/port text fields
  • plugin.xml: Registered projectConfigurable and projectService extensions

Integration

  • PicoCodeStatusBarWidget.kt: Replaced hardcoded DEFAULT_HOST/DEFAULT_PORT with settings service calls
  • PicoCodeToolWindowContent.kt: Removed embedded host/port fields, simplified UI to chat interface only

Example Usage

// All components now use centralized settings
val settings = PicoCodeSettings.getInstance(project)
val url = URL("http://${settings.state.serverHost}:${settings.state.serverPort}/api/projects")

Users configure backend once in project settings; status bar click provides quick access to chat.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • cache-redirector.jetbrains.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /usr/share/gradle-9.2.0/lib/gradle-daemon-main-9.2.0.jar -javaagent:/usr/share/gradle-9.2.0/lib/agents/gradle-instrumentation-agent-9.2.0.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 9.2.0 (dns block)
  • download.jetbrains.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /usr/share/gradle-9.2.0/lib/gradle-daemon-main-9.2.0.jar -javaagent:/usr/share/gradle-9.2.0/lib/agents/gradle-instrumentation-agent-9.2.0.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 9.2.0 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Modifiche richieste (motivazione):
L'utente vuole che cliccando sulla status bar si apra la chat del plugin (tool window "PicoCode RAG") e che ci sia un pannello di opzioni (Settings) in PyCharm per configurare host/port del backend. Inoltre controllare e correggere eventuali registrazioni mancanti in plugin.xml.

Obiettivi tecnici (azione da eseguire nel repo CodeAtCode/PicoCode):

  1. Modificare ide-plugins/src/main/kotlin/com/picocode/PicoCodeStatusBarWidget.kt per aprire il tool window "PicoCode RAG" quando l'utente clicca sulla status bar. Attualmente getClickConsumer() è vuoto. Usare ToolWindowManager.getInstance(project).getToolWindow("PicoCode RAG") e mostrare il tool window; in caso di assenza mostrare un Messages.showInfoMessage. Assicurarsi che invokation avvenga su EDT.

  2. Aggiungere un pannello di configurazione di progetto (Project Settings) che permetta di salvare host e port del server (valori predefiniti localhost:8000). Implementare un servizio Project-level che persiste i valori usando PersistentStateComponent. Creare due file Kotlin nuovi:

    • ide-plugins/src/main/kotlin/com/picocode/PicoCodeSettings.kt : contiene la classe di stato (data class SettingsState) e il ProjectService che implementa PersistentStateComponent con @State annotation.
    • ide-plugins/src/main/kotlin/com/picocode/PicoCodeConfigurable.kt : implementa com.intellij.openapi.options.Configurable (o SearchableConfigurable) e fornisce UI Swing semplice con due JBTextField per host e port e persist li tramite il ProjectService.
  3. Aggiornare ide-plugins/src/main/resources/META-INF/plugin.xml per registrare il projectConfigurable (estensione) in modo che il pannello di opzioni appaia in Settings (Preferences) sotto nome "PicoCode". Aggiungere una entry:

  4. Piccole verifiche e aggiustamenti:

    • Controllare che la factory del tool window abbia lo stesso id testuale "PicoCode RAG" (è definito in plugin.xml), e che PicoCodeToolWindowFactory crei il contenuto correttamente. Non è richiesta modifica alla factory se non si vuole.
    • Assicurarsi che il nuovo codice importi le classi necessarie (ToolWindowManager, Messages, Configurable, PersistentStateComponent, State, Storage, ServiceManager o @service, ecc.)
    • Aggiornare eventuali build.gradle se necessario (ma idealmente non serve)
  5. Test da eseguire (manuale / CI):

    • ./gradlew buildPlugin e verificare che il .zip venga generato in ide-plugins/build/distributions
    • ./gradlew runIde per avviare una sandbox IDE e verificare: il pannello Settings -> cerca "PicoCode" mostra il pannello con host/port, salvare e riaprire; nella status bar compare il widget, cliccandolo si apre il tool window PicoCode RAG (chat)

File da creare/aggiornare (includere contenuto):

--- File: ide-plugins/src/main/kotlin/com/picocode/PicoCodeSettings.kt

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

data class PicoCodeSettingsState(
    var host: String = "localhost",
    var port: Int = 8000
)

@State(name = "PicoCodeSettings", storages = [Storage("picocode.xml")])
class PicoCodeSettingsService(private val project: Project) : PersistentStateComponent<PicoCodeSettingsState> {
    private var state = PicoCodeSettingsState()

    override fun getState(): PicoCodeSettingsState = state

    override fun loadState(state: PicoCodeSettingsState) {
        this.state = state
    }

    companion object {
        fun getInstance(project: Project): PicoCodeSettingsService {
            return project.getService(PicoCodeSettingsService::class.java)
        }
    }
}

--- File: ide-plugins/src/main/kotlin/com/picocode/PicoCodeConfigurable.kt

package com.picocode

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

class PicoCodeConfigurable(private val project: Project) : Configurable {
    private val hostField = JBTextField()
    private val portField = JBTextField()
    private var mainPanel: JPanel? = null

    override fun getDisplayName(): String = "PicoCode"

    override fun createComponent(): JComponent? {
        val settings = PicoCodeSettingsService.getInstance(project).state
        hostField.text = settings.host
        portField.text = settings.port.toString()

        mainPanel = FormBuilder.createFormBuilder()
            .addLabeledComponent("PicoCode Host:", hostField)
            .addLabeledComponent("PicoCode Port:", portField)
            .panel

        return mainPanel
    }

    override fun isModified(): Boolean {
      ...

</details>

*This pull request was created as a result of the following prompt from Copilot chat.*
> Modifiche richieste (motivazione):
> L'utente vuole che cliccando sulla status bar si apra la chat del plugin (tool window "PicoCode RAG") e che ci sia un pannello di opzioni (Settings) in PyCharm per configurare host/port del backend. Inoltre controllare e correggere eventuali registrazioni mancanti in plugin.xml.
> 
> Obiettivi tecnici (azione da eseguire nel repo CodeAtCode/PicoCode):
> 1) Modificare ide-plugins/src/main/kotlin/com/picocode/PicoCodeStatusBarWidget.kt per aprire il tool window "PicoCode RAG" quando l'utente clicca sulla status bar. Attualmente getClickConsumer() è vuoto. Usare ToolWindowManager.getInstance(project).getToolWindow("PicoCode RAG") e mostrare il tool window; in caso di assenza mostrare un Messages.showInfoMessage. Assicurarsi che invokation avvenga su EDT.
> 
> 2) Aggiungere un pannello di configurazione di progetto (Project Settings) che permetta di salvare host e port del server (valori predefiniti localhost:8000). Implementare un servizio Project-level che persiste i valori usando PersistentStateComponent. Creare due file Kotlin nuovi:
>    - ide-plugins/src/main/kotlin/com/picocode/PicoCodeSettings.kt : contiene la classe di stato (data class SettingsState) e il ProjectService che implementa PersistentStateComponent<SettingsState> con @State annotation.
>    - ide-plugins/src/main/kotlin/com/picocode/PicoCodeConfigurable.kt : implementa com.intellij.openapi.options.Configurable (o SearchableConfigurable) e fornisce UI Swing semplice con due JBTextField per host e port e persist li tramite il ProjectService.
> 
> 3) Aggiornare ide-plugins/src/main/resources/META-INF/plugin.xml per registrare il projectConfigurable (estensione) in modo che il pannello di opzioni appaia in Settings (Preferences) sotto nome "PicoCode". Aggiungere una entry: <projectConfigurable instance="com.picocode.PicoCodeConfigurable" displayName="PicoCode" id="com.picocode.settings"/>
> 
> 4) Piccole verifiche e aggiustamenti:
>    - Controllare che la factory del tool window abbia lo stesso id testuale "PicoCode RAG" (è definito in plugin.xml), e che PicoCodeToolWindowFactory crei il contenuto correttamente. Non è richiesta modifica alla factory se non si vuole.
>    - Assicurarsi che il nuovo codice importi le classi necessarie (ToolWindowManager, Messages, Configurable, PersistentStateComponent, State, Storage, ServiceManager o @Service, ecc.)
>    - Aggiornare eventuali build.gradle se necessario (ma idealmente non serve)
> 
> 5) Test da eseguire (manuale / CI):
>    - ./gradlew buildPlugin e verificare che il .zip venga generato in ide-plugins/build/distributions
>    - ./gradlew runIde per avviare una sandbox IDE e verificare: il pannello Settings -> cerca "PicoCode" mostra il pannello con host/port, salvare e riaprire; nella status bar compare il widget, cliccandolo si apre il tool window PicoCode RAG (chat)
> 
> File da creare/aggiornare (includere contenuto):
> 
> --- File: ide-plugins/src/main/kotlin/com/picocode/PicoCodeSettings.kt
> ```kotlin
> 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
> 
> data class PicoCodeSettingsState(
>     var host: String = "localhost",
>     var port: Int = 8000
> )
> 
> @State(name = "PicoCodeSettings", storages = [Storage("picocode.xml")])
> class PicoCodeSettingsService(private val project: Project) : PersistentStateComponent<PicoCodeSettingsState> {
>     private var state = PicoCodeSettingsState()
> 
>     override fun getState(): PicoCodeSettingsState = state
> 
>     override fun loadState(state: PicoCodeSettingsState) {
>         this.state = state
>     }
> 
>     companion object {
>         fun getInstance(project: Project): PicoCodeSettingsService {
>             return project.getService(PicoCodeSettingsService::class.java)
>         }
>     }
> }
> ```
> 
> --- File: ide-plugins/src/main/kotlin/com/picocode/PicoCodeConfigurable.kt
> ```kotlin
> package com.picocode
> 
> import com.intellij.openapi.options.Configurable
> import com.intellij.openapi.project.Project
> import com.intellij.ui.components.JBTextField
> import javax.swing.JComponent
> import javax.swing.JPanel
> import com.intellij.util.ui.FormBuilder
> 
> class PicoCodeConfigurable(private val project: Project) : Configurable {
>     private val hostField = JBTextField()
>     private val portField = JBTextField()
>     private var mainPanel: JPanel? = null
> 
>     override fun getDisplayName(): String = "PicoCode"
> 
>     override fun createComponent(): JComponent? {
>         val settings = PicoCodeSettingsService.getInstance(project).state
>         hostField.text = settings.host
>         portField.text = settings.port.toString()
> 
>         mainPanel = FormBuilder.createFormBuilder()
>             .addLabeledComponent("PicoCode Host:", hostField)
>             .addLabeledComponent("PicoCode Port:", portField)
>             .panel
> 
>         return mainPanel
>     }
> 
>     override fun isModified(): Boolean {
>         val settings = PicoCodeSettingsService.getInstance(project).state
>         val port = portField.text.toIntOrNull() ?: 0
>         return settings.host != hostField.text.trim() || settings.port != port
>     }
> 
>     override fun apply() {
>         val settings = PicoCodeSettingsService.getInstance(project).state
>         settings.host = hostField.text.trim()
>         settings.port = portField.text.toIntOrNull() ?: 8000
>     }
> 
>     override fun reset() {
>         val settings = PicoCodeSettingsService.getInstance(project).state
>         hostField.text = settings.host
>         portField.text = settings.port.toString()
>     }
> 
>     override fun disposeUIResources() {
>         mainPanel = null
>     }
> }
> ```
> 
> --- Modifica: ide-plugins/src/main/kotlin/com/picocode/PicoCodeStatusBarWidget.kt
> Sostituire il metodo getClickConsumer() con il seguente contenuto (apre il tool window "PicoCode RAG"):
> ```kotlin
> override fun getClickConsumer(): Consumer<MouseEvent>? {
>     return Consumer { _ ->
>         ApplicationManager.getApplication().invokeLater {
>             try {
>                 val toolWindow = com.intellij.openapi.wm.ToolWindowManager.getInstance(project).getToolWindow("PicoCode RAG")
>                 if (toolWindow != null) {
>                     toolWindow.show(null)
>                 } else {
>                     com.intellij.openapi.ui.Messages.showInfoMessage(project, "PicoCode tool window not found. Make sure the plugin is installed and restart the IDE.", "PicoCode")
>                 }
>             } catch (e: Exception) {
>                 com.intellij.openapi.ui.Messages.showErrorDialog(project, "Error opening PicoCode tool window: ${e.message}", "PicoCode")
>             }
>         }
>     }
> }
> ```
> 
> --- Modifica: ide-plugins/src/main/resources/META-INF/plugin.xml
> Aggiungere dentro il tag <extensions defaultExtensionNs="com.intellij"> la riga:
> <projectConfigurable instance="com.picocode.PicoCodeConfigurable" displayName="PicoCode" id="com.picocode.settings"/>
> 
> 
> Risultato atteso:
> - Status bar cliccabile che apre la chat
> - Pannello Settings -> PicoCode per configurare host/port salvati per progetto
> - Build e runIde funzionanti
> 
> Esegui le modifiche, crea un ramo di feature, apri una pull request contenente tutti i file modificati/aggiunti. Metti come titolo della PR: "Add Settings panel and make status bar open PicoCode chat" e nella descrizione spiega brevemente le modifiche e come testare (buildPlugin, runIde). Non fare merge automatico.
> 
> Repository target: CodeAtCode/PicoCode
> 

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Copilot AI and others added 2 commits November 12, 2025 11:42
Co-authored-by: Mte90 <403283+Mte90@users.noreply.github.com>
…e UI

Co-authored-by: Mte90 <403283+Mte90@users.noreply.github.com>
Copilot AI changed the title [WIP] Add functionality to open PicoCode chat and settings panel Add status bar click handler and centralized project settings for backend configuration Nov 12, 2025
Copilot AI requested a review from Mte90 November 12, 2025 11:53
Copilot finished work on behalf of Mte90 November 12, 2025 11:53
@Mte90 Mte90 marked this pull request as ready for review November 12, 2025 13:52
@Mte90 Mte90 merged commit c707900 into master Nov 12, 2025
1 check passed
@Mte90 Mte90 deleted the copilot/add-chat-trigger-and-settings branch November 12, 2025 13:53
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants