Skip to content

Commit

Permalink
1.7.1
Browse files Browse the repository at this point in the history
  • Loading branch information
acharneski committed Oct 13, 2024
1 parent 3cf2bd5 commit df12d17
Show file tree
Hide file tree
Showing 12 changed files with 280 additions and 101 deletions.
7 changes: 5 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,30 @@ repositories {

val jetty_version = "11.0.24"
val slf4j_version = "2.0.16"
val skyenet_version = "1.2.9"
val skyenet_version = "1.2.10"
val remoterobot_version = "0.11.23"
val jackson_version = "2.17.2"

dependencies {
implementation("software.amazon.awssdk:bedrock:2.25.9")
implementation("software.amazon.awssdk:bedrockruntime:2.25.9")
implementation("software.amazon.awssdk:s3:2.25.9")
implementation("software.amazon.awssdk:kms:2.25.9")

implementation("org.apache.commons:commons-text:1.11.0")
implementation(group = "com.vladsch.flexmark", name = "flexmark", version = "0.64.8")
implementation("com.googlecode.java-diff-utils:diffutils:1.3.0")
implementation(group = "org.apache.httpcomponents.client5", name = "httpclient5", version = "5.2.3")

implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.1.8")
implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.1.9")
implementation(group = "com.simiacryptus.skyenet", name = "kotlin", version = skyenet_version)
implementation(group = "com.simiacryptus.skyenet", name = "core", version = skyenet_version)
implementation(group = "com.simiacryptus.skyenet", name = "webui", version = skyenet_version)

implementation(group = "com.fasterxml.jackson.core", name = "jackson-databind", version = jackson_version)
implementation(group = "com.fasterxml.jackson.core", name = "jackson-annotations", version = jackson_version)
implementation(group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version = jackson_version)
implementation ("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version")

implementation(group = "org.eclipse.jetty", name = "jetty-server", version = jetty_version)
implementation(group = "org.eclipse.jetty", name = "jetty-servlet", version = jetty_version)
Expand Down
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pluginName=intellij-aicoder
pluginRepositoryUrl=https://github.com/SimiaCryptus/intellij-aicoder
pluginVersion=1.7.0
pluginVersion=1.7.1

jvmArgs=-Xmx8g
org.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=1g
Expand All @@ -9,8 +9,8 @@ org.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=1g
pluginSinceBuild=233
pluginUntilBuild=242.*

platformType = IC
platformVersion=2024.1
platformType = IU
platformVersion=2024.2
gradleVersion=8.10.2

platformPlugins =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ abstract class FileContextAction<T : Any>(

final override fun handle(e: AnActionEvent) {
val config = getConfig(e.project, e)
if (config == null) {
log.warn("No configuration found for ${javaClass.simpleName}")
return
}
val virtualFile = UITools.getSelectedFile(e) ?: UITools.getSelectedFolder(e) ?: return
val project = e.project ?: return
val projectRoot = File(project.basePath!!).toPath()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class RecentCodeEditsAction : ActionGroup() {
override fun getChildren(e: AnActionEvent?): Array<AnAction> {
if (e == null) return emptyArray()
val children = mutableListOf<AnAction>()
for ((instruction, _) in AppSettingsState.instance.getRecentCommands("customEdits").mostUsedHistory) {
for (instruction in AppSettingsState.instance.getRecentCommands("customEdits").getMostRecent(10)) {
val id = children.size + 1
val text = if (id < 10) "_$id: $instruction" else "$id: $instruction"
val element = object : CustomEditAction() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.intellij.openapi.ui.Messages
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.ui.CheckBoxList
import com.intellij.ui.components.JBScrollPane
import javax.swing.JComboBox
import com.intellij.ui.components.JBTextArea
import com.intellij.ui.components.JBTextField
import com.simiacryptus.jopenai.models.ApiModel
Expand All @@ -30,9 +31,11 @@ import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.Executors
import java.util.concurrent.Future
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import javax.swing.*
import java.util.TreeMap


class GenerateDocumentationAction : FileContextAction<GenerateDocumentationAction.Settings>() {
Expand All @@ -53,6 +56,9 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
@Name("AI Instruction")
val transformationMessage = JBTextArea(4, 40)

@Name("Recent Instructions")
val recentInstructions = JComboBox<String>()

@Name("Output File")
val outputFilename = JBTextField()

Expand All @@ -73,11 +79,11 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
val project: Project? = null
)

override fun getConfig(project: Project?, e: AnActionEvent): Settings {
override fun getConfig(project: Project?, e: AnActionEvent): Settings? {
val root = UITools.getSelectedFolder(e)?.toNioPath()
val files = Files.walk(root)
.filter { Files.isRegularFile(it) && !Files.isDirectory(it) }
.toList().filterNotNull().toTypedArray()
.toList().filterNotNull().sortedBy { it.toString() }.toTypedArray()
val settingsUI = SettingsUI().apply {
filesToProcess.setItems(files.toMutableList()) { path ->
root?.relativize(path)?.toString() ?: path.toString()
Expand All @@ -87,28 +93,59 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
}
outputDirectory.text = "docs/"
}
val mruDocumentationInstructions = AppSettingsState.instance.getRecentCommands("DocumentationInstructions")
settingsUI.recentInstructions.model = DefaultComboBoxModel(
mruDocumentationInstructions.getMostRecent(10).map {
"${it.split(" ").first()} ${it.split(" ").drop(1).joinToString(" ")}"
}.toTypedArray()
)
settingsUI.recentInstructions.selectedIndex = -1
settingsUI.recentInstructions.addActionListener { updateUIFromSelection(settingsUI) }
val dialog = DocumentationCompilerDialog(project, settingsUI)
dialog.show()
val settings: UserSettings = dialog.userSettings
settings.singleOutputFile = settingsUI.singleOutputFile.isSelected
settings.outputDirectory = settingsUI.outputDirectory.text
val result = dialog.isOK
settings.filesToProcess = when {
result -> files.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }.toList()
result -> files.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }.sortedBy { it.toString() }.toList()
else -> listOf()
}
if(settings.filesToProcess.isEmpty()) return null
mruDocumentationInstructions.addInstructionToHistory("${settings.outputFilename} ${settings.transformationMessage}")
//.map { path -> return@map root?.resolve(path) }.filterNotNull()
return Settings(settings, project)
}

private fun updateUIFromSelection(settingsUI: SettingsUI) {
val selected = settingsUI.recentInstructions.selectedItem as? String
if (selected != null) {
val parts = selected.split(" ", limit = 2)
if (parts.size == 2) {
settingsUI.outputFilename.text = parts[0]
settingsUI.transformationMessage.text = parts[1]
} else {
settingsUI.transformationMessage.text = selected
}
}
}

override fun processSelection(state: SelectionState, config: Settings?): Array<File> {
if (config?.settings == null) {
// Dialog was cancelled, return empty array
return emptyArray<File>().also {
// Ensure we don't attempt to open any files when dialog is cancelled
return@also
}
}

val selectedFolder = state.selectedFile.toPath()
val gitRoot = TestResultAutofixAction.findGitRoot(selectedFolder) ?: selectedFolder
val outputDirectory = config?.settings?.outputDirectory ?: "docs/"
var outputPath =
selectedFolder.resolve(config?.settings?.outputFilename ?: "compiled_documentation.md")
val relativePath = gitRoot.relativize(outputPath)
outputPath = gitRoot.resolve(outputDirectory).resolve(relativePath)
outputPath = gitRoot.resolve(outputDirectory).resolve(relativePath)
if (outputPath.toFile().exists()) {
val extension = outputPath.toString().split(".").last()
val name = outputPath.toString().split(".").dropLast(1).joinToString(".")
Expand All @@ -118,14 +155,13 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
outputPath = selectedFolder.resolve("$name.$fileIndex.$extension")
}
val executorService = Executors.newFixedThreadPool(4)
outputPath.parent.toFile().mkdirs()
val transformationMessage = config?.settings?.transformationMessage ?: "Create user documentation"
val markdownContent = StringBuilder()
val markdownContent = TreeMap<String, String>()
try {
val selectedPaths = config?.settings?.filesToProcess ?: listOf()
val selectedPaths = (config?.settings?.filesToProcess ?: listOf()).sortedBy { it.toString() }
val partitionedPaths = Files.walk(selectedFolder)
.filter { Files.isRegularFile(it) && !Files.isDirectory(it) }
.toList().groupBy { selectedPaths.contains(it) }
.toList().sortedBy { it.toString() }.groupBy { selectedPaths.contains(it) }
val pathList = partitionedPaths[true]
?.toList()?.filterNotNull()
?.map<Path, Future<Path>> { path ->
Expand Down Expand Up @@ -172,12 +208,19 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
}
}?.filterNotNull() ?: listOf()
if (config?.settings?.singleOutputFile == true) {
Files.write(outputPath, markdownContent.toString().toByteArray())
val sortedContent = markdownContent.entries.joinToString("\n\n") { (path, content) ->
"# $path\n\n$content"
}
outputPath.parent.toFile().mkdirs()
outputPath.parent.toFile().mkdirs()
Files.write(outputPath, sortedContent.toByteArray())
open(config.project!!, outputPath)
return arrayOf(outputPath.toFile())
} else {
val outputDir = selectedFolder.resolve(outputDirectory)
outputDir.toFile().mkdirs()
open(config?.project!!, selectedFolder.resolve(outputDirectory))
return pathList.toList().map { it.toFile() }.toTypedArray()
return pathList.map { it.toFile() }.toTypedArray()
}
} finally {
executorService.shutdown()
Expand All @@ -192,11 +235,10 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
gitRoot: Path,
outputDirectory: String,
outputPath: Path,
markdownContent: StringBuilder
markdownContent: TreeMap<String, String>
) {
if (config?.settings?.singleOutputFile == true) {
markdownContent.append("# ${selectedFolder.relativize(path)}\n\n")
markdownContent.append(transformContent.replace("(?s)(?<![^\\n])#".toRegex(), "\n##"))
markdownContent[selectedFolder.relativize(path).toString()] = transformContent.replace("(?s)(?<![^\\n])#".toRegex(), "\n##")
} else {
var individualOutputPath = /*selectedFolder*/ selectedFolder.relativize(
path.parent.resolve(
Expand Down Expand Up @@ -281,38 +323,49 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
}
}

class DocumentationCompilerDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) {
inner class DocumentationCompilerDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) {
val userSettings = UserSettings()
private val selectedInstruction = AtomicReference<String>()

init {
title = "Compile Documentation"
// Set the default values for the UI elements from userSettings
settingsUI.transformationMessage.text = userSettings.transformationMessage
settingsUI.outputFilename.text = userSettings.outputFilename
settingsUI.outputDirectory.text = userSettings.outputDirectory
settingsUI.singleOutputFile.isSelected = userSettings.singleOutputFile
settingsUI.singleOutputFile.isSelected = userSettings.singleOutputFile
settingsUI.recentInstructions.addActionListener {
val selected = settingsUI.recentInstructions.selectedItem as? String
selected?.let {
updateUIFromSelection(settingsUI)
}
}
init()
}

override fun createCenterPanel(): JComponent {
val panel = JPanel(BorderLayout()).apply {
val filesScrollPane = JBScrollPane(settingsUI.filesToProcess).apply {
preferredSize = Dimension(600, 400) // Increase the size for better visibility
preferredSize = Dimension(600, 400) // Increase the size for better visibility
}
add(filesScrollPane, BorderLayout.CENTER) // Make the files list the dominant element

val optionsPanel = JPanel().apply {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
border = BorderFactory.createEmptyBorder(10, 10, 10, 10) // Add some padding
border = BorderFactory.createEmptyBorder(10, 10, 10, 10) // Add some padding
add(JLabel("Recent Instructions"))
add(settingsUI.recentInstructions)
add(Box.createVerticalStrut(10))
add(JLabel("AI Instruction"))
add(settingsUI.transformationMessage)
add(Box.createVerticalStrut(10)) // Add some vertical spacing
add(Box.createVerticalStrut(10))
add(Box.createVerticalStrut(10)) // Add some vertical spacing
add(JLabel("Output File"))
add(settingsUI.outputFilename)
add(Box.createVerticalStrut(10))
add(Box.createVerticalStrut(10))
add(JLabel("Output Directory"))
add(settingsUI.outputDirectory)
add(Box.createVerticalStrut(10))
add(Box.createVerticalStrut(10))
add(settingsUI.singleOutputFile)
}
add(optionsPanel, BorderLayout.SOUTH)
Expand All @@ -321,9 +374,9 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
}

override fun doOKAction() {
if (!validateInput()) {
return
}
if (!validateInput()) {
return
}
super.doOKAction()
userSettings.transformationMessage = settingsUI.transformationMessage.text
userSettings.outputFilename = settingsUI.outputFilename.text
Expand All @@ -334,21 +387,22 @@ class GenerateDocumentationAction : FileContextAction<GenerateDocumentationActio
settingsUI.filesToProcess.items.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }
userSettings.singleOutputFile = settingsUI.singleOutputFile.isSelected
}
private fun validateInput(): Boolean {
if (settingsUI.transformationMessage.text.isBlank()) {
Messages.showErrorDialog("AI Instruction cannot be empty", "Input Error")
return false
}
if (settingsUI.outputFilename.text.isBlank()) {
Messages.showErrorDialog("Output File cannot be empty", "Input Error")
return false
}
if (settingsUI.outputDirectory.text.isBlank()) {
Messages.showErrorDialog("Output Directory cannot be empty", "Input Error")
return false
}
return true
}

private fun validateInput(): Boolean {
if (settingsUI.transformationMessage.text.isBlank()) {
Messages.showErrorDialog("AI Instruction cannot be empty", "Input Error")
return false
}
if (settingsUI.outputFilename.text.isBlank()) {
Messages.showErrorDialog("Output File cannot be empty", "Input Error")
return false
}
if (settingsUI.outputDirectory.text.isBlank()) {
Messages.showErrorDialog("Output Directory cannot be empty", "Input Error")
return false
}
return true
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import java.io.File
import java.io.FileInputStream
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
import javax.swing.JTextArea

class GenerateRelatedFileAction : FileContextAction<GenerateRelatedFileAction.Settings>() {
override fun getActionUpdateThread() = ActionUpdateThread.BGT
override fun isEnabled(event: AnActionEvent): Boolean {
if (UITools.getSelectedFiles(event).size != 1) return false
return super.isEnabled(event)
return UITools.getSelectedFiles(event).size == 1 && super.isEnabled(event)
}

data class ProjectFile(
Expand Down Expand Up @@ -121,7 +121,7 @@ class GenerateRelatedFileAction : FileContextAction<GenerateRelatedFileAction.Se

)
)
val response = api.chat(chatRequest, model).choices.first().message?.content?.trim()
val response = api.chat(chatRequest, model).choices.firstOrNull()?.message?.content?.trim() ?: throw IllegalStateException("No response from API")
var outputPath = baseFile.path
val header = response?.split("\n")?.first()
var body = response?.split("\n")?.drop(1)?.joinToString("\n")?.trim()
Expand All @@ -141,8 +141,8 @@ class GenerateRelatedFileAction : FileContextAction<GenerateRelatedFileAction.Se

companion object {
fun open(project: Project, outputPath: Path) {
lateinit var function: () -> Unit
function = {
val functionRef = AtomicReference<(() -> Unit)?>(null)
val function: () -> Unit = {
val file = outputPath.toFile()
if (file.exists()) {
// Ensure the IDE is ready for file operations
Expand All @@ -154,17 +154,18 @@ class GenerateRelatedFileAction : FileContextAction<GenerateRelatedFileAction.Se
val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file)
virtualFile?.let {
FileEditorManager.getInstance(project).openFile(it, true)
} ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS)
} ?: scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS)
} else {
scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS)
scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS)
}
}
} else {
scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS)
scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS)
}
}
functionRef.set(function)
scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS)
}

}
}
}
Loading

0 comments on commit df12d17

Please sign in to comment.