generated from JetBrains/intellij-platform-plugin-template
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
147 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
src/main/kotlin/cc/unitmesh/devti/context/chunks/SimilarChunkContext.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package cc.unitmesh.devti.context.chunks | ||
|
||
import cc.unitmesh.devti.context.base.LLMQueryContext | ||
import com.google.gson.Gson | ||
import com.intellij.lang.Commenter | ||
import com.intellij.lang.Language | ||
import com.intellij.lang.LanguageCommenters | ||
|
||
class SimilarChunkContext(val language: Language, val paths: List<String>?, val chunks: List<String>?) : LLMQueryContext { | ||
override fun toQuery(): String { | ||
val commenter: Commenter? = LanguageCommenters.INSTANCE.forLanguage(language) | ||
val commentPrefix: String? = commenter?.lineCommentPrefix | ||
|
||
if (paths == null || chunks == null) return "" | ||
|
||
val filteredPairs = paths.zip(chunks).toList() | ||
|
||
val queryBuilder = StringBuilder() | ||
for ((path, chunk) in filteredPairs) { | ||
val commentedCode = commentCode(chunk, commentPrefix) | ||
queryBuilder.append("$commentPrefix Compare this snippet from $commentPrefix:\n") | ||
queryBuilder.append(commentedCode) | ||
queryBuilder.append("\n") | ||
} | ||
|
||
return queryBuilder.toString().trim() | ||
} | ||
|
||
override fun toJson(): String = Gson().toJson( | ||
mapOf( | ||
"paths" to paths, | ||
"chunks" to chunks | ||
) | ||
) | ||
|
||
private fun commentCode(code: String, commentSymbol: String?): String { | ||
if (commentSymbol == null) return code | ||
return code.split("\n").joinToString("\n") { | ||
"$commentSymbol $commentSymbol" | ||
} | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
src/main/kotlin/cc/unitmesh/devti/context/chunks/SimilarChunksWithPaths.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package cc.unitmesh.devti.context.chunks | ||
|
||
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager | ||
import com.intellij.openapi.fileTypes.FileType | ||
import com.intellij.openapi.roots.ProjectFileIndex | ||
import com.intellij.openapi.roots.ProjectRootManager | ||
import com.intellij.openapi.vfs.VfsUtilCore | ||
import com.intellij.openapi.vfs.VirtualFile | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.PsiManager | ||
import java.io.File | ||
|
||
class SimilarChunksWithPaths() { | ||
companion object { | ||
val INSTANCE: SimilarChunksWithPaths = SimilarChunksWithPaths() | ||
private const val CHUNK_SIZE = 60 | ||
private const val MAX_RELEVANT_FILES = 20 | ||
} | ||
|
||
fun similarChunksWithPaths(element: PsiElement): SimilarChunkContext { | ||
val mostRecentFiles: List<VirtualFile> = getMostRecentFiles(element) | ||
val mostRecentFilesRelativePaths: List<String> = mostRecentFiles.map { INSTANCE.relativePathTo(it, element)!! } | ||
val chunks: List<List<String>> = extractChunks(element, mostRecentFiles) | ||
val jaccardSimilarities: List<List<Double>> = tokenLevelJaccardSimilarity(chunks, element) | ||
val paths: MutableList<String> = ArrayList() | ||
val chunksList: MutableList<String> = ArrayList() | ||
|
||
jaccardSimilarities.forEachIndexed { index, list -> | ||
val maxIndex = list.indexOf(list.maxOrNull()!!) | ||
paths.add(mostRecentFilesRelativePaths[index]) | ||
chunksList.add(chunks[index][maxIndex]) | ||
} | ||
|
||
return SimilarChunkContext(element.language, paths, chunksList) | ||
} | ||
|
||
private fun tokenLevelJaccardSimilarity(chunks: List<List<String>>, element: PsiElement): List<List<Double>> { | ||
val currentFileTokens: Set<String> = tokenize(element.containingFile.text).toSet() | ||
return chunks.map { list -> | ||
list.map { | ||
val tokenizedFile: Set<String> = tokenize(it).toSet() | ||
jaccardSimilarity(currentFileTokens, tokenizedFile) | ||
} | ||
} | ||
} | ||
|
||
private fun relativePathTo(relativeFile: VirtualFile, element: PsiElement): String? { | ||
val fileIndex: ProjectFileIndex = ProjectRootManager.getInstance(element.project).fileIndex | ||
var contentRoot: VirtualFile? = fileIndex.getContentRootForFile(relativeFile) | ||
if (contentRoot == null) { | ||
contentRoot = fileIndex.getClassRootForFile(relativeFile) | ||
} | ||
|
||
return contentRoot?.let { VfsUtilCore.getRelativePath(relativeFile, it, File.separatorChar) } | ||
} | ||
|
||
private fun tokenize(chunk: String): List<String> { | ||
return chunk.split(Regex("[^a-zA-Z0-9]")) | ||
.filter { it.isNotBlank() } | ||
} | ||
|
||
private fun jaccardSimilarity(set1: Set<String>, set2: Set<String>): Double { | ||
val intersectionSize: Int = set1.intersect(set2).size | ||
val unionSize: Int = set1.union(set2).size | ||
return intersectionSize.toDouble() / unionSize.toDouble() | ||
} | ||
|
||
private fun extractChunks(element: PsiElement, mostRecentFiles: List<VirtualFile>): List<List<String>> { | ||
val psiManager: PsiManager = PsiManager.getInstance(element.project) | ||
return mostRecentFiles.mapNotNull { file -> | ||
val psiFile = psiManager.findFile(file) | ||
psiFile?.text?.split("\n", limit = CHUNK_SIZE)?.chunked(CHUNK_SIZE)?.flatten() | ||
} | ||
} | ||
|
||
private fun getMostRecentFiles(element: PsiElement): List<VirtualFile> { | ||
val fileType: FileType? = element.containingFile?.fileType | ||
if (element.containingFile == null || fileType == null) { | ||
return emptyList() | ||
} | ||
val recentFiles: List<VirtualFile> = EditorHistoryManager.getInstance(element.project).fileList.filter { file -> | ||
file.isValid && file.fileType == fileType | ||
} | ||
val start = (recentFiles.size - MAX_RELEVANT_FILES + 1).coerceAtLeast(0) | ||
val end = (recentFiles.size - 1).coerceAtLeast(0) | ||
return recentFiles.subList(start, end) | ||
} | ||
} |
28 changes: 1 addition & 27 deletions
28
src/main/resources/intentionDescriptions/AIAssistantIntention/description.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1 @@ | ||
<html> | ||
<body> | ||
Write your description here. | ||
Start the description with a verb in 3rd person singular, like reports, detects, highlights. | ||
In the first sentence, briefly explain what exactly the inspection helps you detect. | ||
Make sure the sentence is not very long and complicated. | ||
<p> | ||
The first sentence must be in a dedicated paragraph separated from the rest of the text. This will make the | ||
description easier to read. | ||
Make sure the description doesn’t just repeat the inspection title. | ||
</p> | ||
<p> | ||
See https://jetbrains.design/intellij/text/inspections/#descriptions for more information. | ||
</p> | ||
<p> | ||
Embed code snippets: | ||
</p> | ||
<pre><code> | ||
// automatically highlighted according to inspection registration 'language' attribute | ||
</code></pre> | ||
<!-- tooltip end --> | ||
<p>Text after this comment will only be shown in the settings of the inspection.</p> | ||
|
||
<p>To open related settings directly from the description, add a link with `settings://$` optionally followed by `?$` to | ||
pre-select a UI element.</p> | ||
</body> | ||
</html> | ||
Invoke AutoDev Action in here. |