Skip to content

Commit 2f03a16

Browse files
committed
feat(prompts): retrieve common branch from svn repositories
Show branch notification only if branch variable is used.
1 parent a923a09 commit 2f03a16

File tree

4 files changed

+67
-40
lines changed

4 files changed

+67
-40
lines changed

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/AICommitsUtils.kt

Lines changed: 61 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@ import com.intellij.openapi.diff.impl.patch.IdeaTextPatchBuilder
1313
import com.intellij.openapi.diff.impl.patch.UnifiedDiffWriter
1414
import com.intellij.openapi.project.Project
1515
import com.intellij.openapi.vcs.changes.Change
16+
import com.intellij.openapi.vfs.VfsUtilCore
1617
import com.intellij.tasks.TaskManager
1718
import com.intellij.util.text.DateFormatUtil
19+
import com.intellij.vcsUtil.VcsUtil
20+
import git4idea.GitVcs
1821
import git4idea.repo.GitRepositoryManager
1922
import kotlinx.coroutines.Dispatchers
2023
import kotlinx.coroutines.withContext
24+
import org.jetbrains.idea.svn.SvnUtil
25+
import org.jetbrains.idea.svn.SvnVcs
2126
import java.io.StringWriter
2227
import java.nio.file.FileSystems
2328
import java.util.*
@@ -39,11 +44,11 @@ object AICommitsUtils {
3944
return false
4045
}
4146

42-
fun constructPrompt(promptContent: String, diff: String, branch: String, hint: String?, project: Project): String {
47+
fun constructPrompt(promptContent: String, diff: String, branch: String?, hint: String?, project: Project): String {
4348
var content = promptContent
4449
val locale = project.service<ProjectSettings>().locale
4550
content = content.replace("{locale}", locale.getDisplayLanguage(Locale.ENGLISH))
46-
content = content.replace("{branch}", branch)
51+
content = replaceBranch(content, branch)
4752
content = replaceHint(content, hint)
4853

4954
// TODO @Blarc: If TaskManager is null, the prompt might be incorrect...
@@ -62,6 +67,18 @@ object AICommitsUtils {
6267
}
6368
}
6469

70+
fun replaceBranch(promptContent: String, branch: String?): String {
71+
if (promptContent.contains("{branch}")) {
72+
if (branch != null) {
73+
return promptContent.replace("{branch}", branch)
74+
} else {
75+
sendNotification(Notification.noCommonBranch())
76+
return promptContent.replace("{branch}", "main")
77+
}
78+
}
79+
return promptContent
80+
}
81+
6582
fun replaceHint(promptContent: String, hint: String?): String {
6683
val hintRegex = Regex("\\{[^{}]*(\\\$hint)[^{}]*}")
6784

@@ -78,25 +95,29 @@ object AICommitsUtils {
7895
return promptContent.replace("{hint}", hint.orEmpty())
7996
}
8097

81-
suspend fun getCommonBranchOrDefault(changes: List<Change>, project: Project, showNotification: Boolean = true): String {
82-
var branch = getCommonBranch(changes, project)
83-
if (branch == null) {
84-
// Can't show notification in edit prompt dialog
85-
if (showNotification) {
86-
sendNotification(Notification.noCommonBranch())
87-
}
88-
// hardcoded fallback branch
89-
branch = "main"
90-
}
91-
return branch
92-
}
93-
9498
suspend fun getCommonBranch(changes: List<Change>, project: Project): String? {
95-
val repositoryManager = GitRepositoryManager.getInstance(project)
9699
return withContext(Dispatchers.IO) {
97-
changes.map {
98-
repositoryManager.getRepositoryForFile(it.virtualFile)?.currentBranchName
99-
}.filterNotNull().groupingBy { it }.eachCount().maxByOrNull { it.value }?.key
100+
changes.mapNotNull {
101+
it.virtualFile?.let { virtualFile ->
102+
VcsUtil.getVcsFor(project, virtualFile)?.let { vcs ->
103+
when (vcs) {
104+
is SvnVcs -> {
105+
SvnUtil.getUrl(vcs, VfsUtilCore.virtualToIoFile(virtualFile))?.let { url ->
106+
extractSvnBranchName(url.toDecodedString())
107+
}
108+
}
109+
is GitVcs -> {
110+
GitRepositoryManager.getInstance(project)
111+
.getRepositoryForFile(it.virtualFile)
112+
?.currentBranchName
113+
}
114+
else -> {
115+
null
116+
}
117+
}
118+
}
119+
}
120+
}.groupingBy { it }.eachCount().maxByOrNull { it.value }?.key
100121
}
101122
}
102123

@@ -140,22 +161,27 @@ object AICommitsUtils {
140161
.joinToString("\n")
141162
}
142163

143-
// TODO @Blarc: This only works for OpenAI
144-
// fun isPromptTooLarge(prompt: String): Boolean {
145-
// val registry = Encodings.newDefaultEncodingRegistry()
146-
//
147-
// /*
148-
// * Try to find the model type based on the model id by finding the longest matching model type
149-
// * If no model type matches, let the request go through and let the OpenAI API handle it
150-
// */
151-
// val modelType = ModelType.entries
152-
// .filter { AppSettings2.instance.getActiveLLMClient().modelId.contains(it.name) }
153-
// .maxByOrNull { it.name.length }
154-
// ?: return false
155-
//
156-
// val encoding = registry.getEncoding(modelType.encodingType)
157-
// return encoding.countTokens(prompt) > modelType.maxContextLength
158-
// }
164+
private fun extractSvnBranchName(url: String): String? {
165+
val normalizedUrl = url.lowercase()
166+
167+
// Standard SVN layout: repository/trunk, repository/branches/name, repository/tags/name
168+
return when {
169+
normalizedUrl.contains("/branches/") -> {
170+
val branchPart = url.substringAfter("/branches/")
171+
val endIndex = branchPart.indexOf('/')
172+
if (endIndex > 0) branchPart.substring(0, endIndex) else branchPart
173+
}
174+
175+
normalizedUrl.contains("/tags/") -> {
176+
val tagPart = url.substringAfter("/tags/")
177+
val endIndex = tagPart.indexOf('/')
178+
if (endIndex > 0) "tag: ${tagPart.substring(0, endIndex)}" else "tag: $tagPart"
179+
}
180+
181+
normalizedUrl.contains("/trunk") -> "trunk"
182+
else -> null // fallback: no branch concept available
183+
}
184+
}
159185

160186
suspend fun retrieveToken(title: String): OneTimeString? {
161187
val credentialAttributes = getCredentialAttributes(title)

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/clients/LLMClientService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.github.blarc.ai.commits.intellij.plugin.settings.clients
33
import com.github.blarc.ai.commits.intellij.plugin.AICommitsBundle.message
44
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.computeDiff
55
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.constructPrompt
6-
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.getCommonBranchOrDefault
6+
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.getCommonBranch
77
import com.github.blarc.ai.commits.intellij.plugin.notifications.Notification
88
import com.github.blarc.ai.commits.intellij.plugin.notifications.sendNotification
99
import com.github.blarc.ai.commits.intellij.plugin.settings.AppSettings2
@@ -96,7 +96,7 @@ abstract class LLMClientService<C : LLMClientConfiguration>(private val cs: Coro
9696
return@withBackgroundProgress
9797
}
9898

99-
val branch = getCommonBranchOrDefault(includedChanges, project)
99+
val branch = getCommonBranch(includedChanges, project)
100100
val prompt = constructPrompt(project.service<ProjectSettings>().activePrompt.content, diff, branch, commitMessage.text, project)
101101

102102
makeRequest(clientConfiguration, prompt, onSuccess = {

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/prompts/PromptTable.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import ai.grazie.utils.applyIf
44
import com.github.blarc.ai.commits.intellij.plugin.AICommitsBundle.message
55
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils
66
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.computeDiff
7-
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.getCommonBranchOrDefault
7+
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.getCommonBranch
88
import com.github.blarc.ai.commits.intellij.plugin.createColumn
99
import com.github.blarc.ai.commits.intellij.plugin.notBlank
1010
import com.github.blarc.ai.commits.intellij.plugin.settings.AppSettings2
@@ -119,7 +119,7 @@ class PromptTable(private val cs: CoroutineScope) {
119119
val promptHintTextField = JBTextField()
120120
val promptContentTextArea = JBTextArea()
121121
val promptPreviewTextArea = JBTextArea()
122-
lateinit var branch: String
122+
var branch: String? = null
123123
lateinit var diff: String
124124
lateinit var project: Project
125125
private val logger = Logger.getInstance(PromptDialog::class.java)
@@ -233,7 +233,7 @@ class PromptTable(private val cs: CoroutineScope) {
233233
logger.warn("No changes found for the current branch.")
234234
}
235235

236-
branch = getCommonBranchOrDefault(changes, project, false)
236+
branch = getCommonBranch(changes, project)
237237
diff = computeDiff(changes, true, project)
238238

239239
withContext(Dispatchers.EDT) {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
Read more: https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html -->
6060
<depends>com.intellij.modules.platform</depends>
6161
<depends>Git4Idea</depends>
62+
<depends>Subversion</depends>
6263

6364
<applicationListeners>
6465

0 commit comments

Comments
 (0)