Skip to content

Commit e19324f

Browse files
committed
refactor(devti): extract patch conversion logic into separate utility
- Move createChange and getAbsolutePath functions to PatchConverter object - Update import statements and remove unnecessary code from AgentStateService - Improve code organization and readability by separating concerns
1 parent 072c25d commit e19324f

File tree

2 files changed

+120
-104
lines changed

2 files changed

+120
-104
lines changed

core/src/main/kotlin/cc/unitmesh/devti/observer/agent/AgentStateService.kt

Lines changed: 3 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,13 @@ import cc.unitmesh.devti.observer.plan.AgentTaskEntry
88
import cc.unitmesh.devti.observer.plan.MarkdownPlanParser
99
import cc.unitmesh.devti.observer.plan.PlanUpdateListener
1010
import cc.unitmesh.devti.settings.AutoDevSettingsState
11+
import cc.unitmesh.devti.util.PatchConverter
1112
import cc.unitmesh.devti.util.parser.MarkdownCodeHelper
1213
import com.intellij.openapi.application.ApplicationManager
13-
import com.intellij.openapi.application.ReadAction
1414
import com.intellij.openapi.components.Service
1515
import com.intellij.openapi.diagnostic.logger
1616
import com.intellij.openapi.diff.impl.patch.TextFilePatch
17-
import com.intellij.openapi.diff.impl.patch.apply.GenericPatchApplier
18-
import com.intellij.openapi.fileEditor.FileDocumentManager
1917
import com.intellij.openapi.project.Project
20-
import com.intellij.openapi.util.ThrowableComputable
21-
import com.intellij.openapi.vcs.FilePath
22-
import com.intellij.openapi.vcs.FileStatus
23-
import com.intellij.openapi.vcs.VcsBundle
24-
import com.intellij.openapi.vcs.VcsException
25-
import com.intellij.openapi.vcs.changes.Change
26-
import com.intellij.openapi.vcs.changes.ContentRevision
27-
import com.intellij.openapi.vcs.changes.CurrentContentRevision
28-
import com.intellij.openapi.vcs.changes.TextRevisionNumber
29-
import com.intellij.openapi.vcs.history.VcsRevisionNumber
30-
import com.intellij.openapi.vfs.VirtualFile
31-
import com.intellij.vcsUtil.VcsUtil
32-
import org.jetbrains.annotations.NonNls
3318
import java.io.File
3419
import java.io.IOException
3520

@@ -52,15 +37,15 @@ class AgentStateService(val project: Project) {
5237
fun addToChange(patch: TextFilePatch) {
5338
val baseDir = File(project.basePath!!)
5439
if (patch.afterName != null) {
55-
val newChangePath = getAbsolutePath(baseDir, patch.afterName).canonicalPath
40+
val newChangePath = PatchConverter.getAbsolutePath(baseDir, patch.afterName).canonicalPath
5641
state.changes.removeIf {
5742
val afterRevision = it.afterRevision
5843
afterRevision != null && File(afterRevision.file.path).canonicalPath == newChangePath
5944
}
6045
}
6146

6247
try {
63-
val change = createChange(patch)
48+
val change = PatchConverter.createChange(project, patch)
6449
state.changes.add(change)
6550

6651
ApplicationManager.getApplication().messageBus
@@ -71,92 +56,6 @@ class AgentStateService(val project: Project) {
7156
}
7257
}
7358

74-
private fun createChange(patch: TextFilePatch): Change {
75-
val baseDir = File(project.basePath!!)
76-
val beforePath = patch.beforeName
77-
val afterPath = patch.afterName
78-
79-
val fileStatus = when {
80-
patch.isNewFile -> {
81-
FileStatus.ADDED
82-
}
83-
patch.isDeletedFile -> {
84-
FileStatus.DELETED
85-
}
86-
else -> {
87-
FileStatus.MODIFIED
88-
}
89-
}
90-
91-
val beforeFilePath = VcsUtil.getFilePath(getAbsolutePath(baseDir, beforePath), false)
92-
val afterFilePath = VcsUtil.getFilePath(getAbsolutePath(baseDir, afterPath), false)
93-
94-
var beforeRevision: ContentRevision? = null
95-
if (fileStatus !== FileStatus.ADDED) {
96-
beforeRevision = object : CurrentContentRevision(beforeFilePath) {
97-
override fun getRevisionNumber(): VcsRevisionNumber {
98-
return TextRevisionNumber(VcsBundle.message("local.version.title"))
99-
}
100-
}
101-
}
102-
103-
var afterRevision: ContentRevision? = null
104-
if (fileStatus !== FileStatus.DELETED) {
105-
afterRevision = object : CurrentContentRevision(beforeFilePath) {
106-
override fun getRevisionNumber(): VcsRevisionNumber =
107-
TextRevisionNumber(VcsBundle.message("local.version.title"))
108-
109-
override fun getVirtualFile(): VirtualFile? = afterFilePath.virtualFile
110-
override fun getFile(): FilePath = afterFilePath
111-
override fun getContent(): @NonNls String? {
112-
when {
113-
patch.isNewFile -> {
114-
return patch.singleHunkPatchText
115-
}
116-
patch.isDeletedFile -> {
117-
return null
118-
}
119-
else -> {
120-
val localContent: String = loadLocalContent()
121-
val appliedPatch = GenericPatchApplier.apply(localContent, patch.hunks)
122-
/// sometimes llm will return a wrong patch which the content is not correct
123-
if (appliedPatch != null) {
124-
return appliedPatch.patchedText
125-
}
126-
127-
return patch.singleHunkPatchText
128-
}
129-
}
130-
}
131-
132-
@Throws(VcsException::class)
133-
private fun loadLocalContent(): String {
134-
return ReadAction.compute<String?, VcsException?>(ThrowableComputable {
135-
val file: VirtualFile? = beforeFilePath.virtualFile
136-
if (file == null) return@ThrowableComputable null
137-
val doc = FileDocumentManager.getInstance().getDocument(file)
138-
if (doc == null) return@ThrowableComputable null
139-
doc.text
140-
})
141-
}
142-
}
143-
}
144-
145-
return Change(beforeRevision, afterRevision, fileStatus)
146-
}
147-
148-
private fun getAbsolutePath(baseDir: File, relativePath: String): File {
149-
var file: File?
150-
try {
151-
file = File(baseDir, relativePath).getCanonicalFile()
152-
} catch (e: IOException) {
153-
logger<AgentStateService>().info(e)
154-
file = File(baseDir, relativePath)
155-
}
156-
157-
return file
158-
}
159-
16059
fun buildOriginIntention(): String? {
16160
val intention = state.messages
16261
.firstOrNull { it.role.lowercase() == "user" }
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package cc.unitmesh.devti.util
2+
3+
import cc.unitmesh.devti.observer.agent.AgentStateService
4+
import com.intellij.openapi.application.ReadAction
5+
import com.intellij.openapi.diagnostic.logger
6+
import com.intellij.openapi.diff.impl.patch.TextFilePatch
7+
import com.intellij.openapi.diff.impl.patch.apply.GenericPatchApplier
8+
import com.intellij.openapi.fileEditor.FileDocumentManager
9+
import com.intellij.openapi.project.Project
10+
import com.intellij.openapi.util.ThrowableComputable
11+
import com.intellij.openapi.vcs.FilePath
12+
import com.intellij.openapi.vcs.FileStatus
13+
import com.intellij.openapi.vcs.VcsBundle
14+
import com.intellij.openapi.vcs.VcsException
15+
import com.intellij.openapi.vcs.changes.Change
16+
import com.intellij.openapi.vcs.changes.ContentRevision
17+
import com.intellij.openapi.vcs.changes.CurrentContentRevision
18+
import com.intellij.openapi.vcs.changes.TextRevisionNumber
19+
import com.intellij.openapi.vcs.history.VcsRevisionNumber
20+
import com.intellij.openapi.vfs.VirtualFile
21+
import com.intellij.vcsUtil.VcsUtil
22+
import org.jetbrains.annotations.NonNls
23+
import java.io.File
24+
import java.io.IOException
25+
26+
object PatchConverter {
27+
fun getAbsolutePath(baseDir: File, relativePath: String): File {
28+
var file: File?
29+
try {
30+
file = File(baseDir, relativePath).getCanonicalFile()
31+
} catch (e: IOException) {
32+
logger<PatchConverter>().info(e)
33+
file = File(baseDir, relativePath)
34+
}
35+
36+
return file
37+
}
38+
39+
fun createChange(project: Project, patch: TextFilePatch): Change {
40+
val baseDir = File(project.basePath!!)
41+
val beforePath = patch.beforeName
42+
val afterPath = patch.afterName
43+
44+
val fileStatus = when {
45+
patch.isNewFile -> {
46+
FileStatus.ADDED
47+
}
48+
49+
patch.isDeletedFile -> {
50+
FileStatus.DELETED
51+
}
52+
53+
else -> {
54+
FileStatus.MODIFIED
55+
}
56+
}
57+
58+
val beforeFilePath = VcsUtil.getFilePath(getAbsolutePath(baseDir, beforePath), false)
59+
val afterFilePath = VcsUtil.getFilePath(getAbsolutePath(baseDir, afterPath), false)
60+
61+
var beforeRevision: ContentRevision? = null
62+
if (fileStatus !== FileStatus.ADDED) {
63+
beforeRevision = object : CurrentContentRevision(beforeFilePath) {
64+
override fun getRevisionNumber(): VcsRevisionNumber {
65+
return TextRevisionNumber(VcsBundle.message("local.version.title"))
66+
}
67+
}
68+
}
69+
70+
var afterRevision: ContentRevision? = null
71+
if (fileStatus !== FileStatus.DELETED) {
72+
afterRevision = object : CurrentContentRevision(beforeFilePath) {
73+
override fun getRevisionNumber(): VcsRevisionNumber =
74+
TextRevisionNumber(VcsBundle.message("local.version.title"))
75+
76+
override fun getVirtualFile(): VirtualFile? = afterFilePath.virtualFile
77+
override fun getFile(): FilePath = afterFilePath
78+
override fun getContent(): @NonNls String? {
79+
when {
80+
patch.isNewFile -> {
81+
return patch.singleHunkPatchText
82+
}
83+
84+
patch.isDeletedFile -> {
85+
return null
86+
}
87+
88+
else -> {
89+
val localContent: String = loadLocalContent()
90+
val appliedPatch = GenericPatchApplier.apply(localContent, patch.hunks)
91+
/// sometimes llm will return a wrong patch which the content is not correct
92+
if (appliedPatch != null) {
93+
return appliedPatch.patchedText
94+
}
95+
96+
return patch.singleHunkPatchText
97+
}
98+
}
99+
}
100+
101+
@Throws(VcsException::class)
102+
private fun loadLocalContent(): String {
103+
return ReadAction.compute<String?, VcsException?>(ThrowableComputable {
104+
val file: VirtualFile? = beforeFilePath.virtualFile
105+
if (file == null) return@ThrowableComputable null
106+
val doc = FileDocumentManager.getInstance().getDocument(file)
107+
if (doc == null) return@ThrowableComputable null
108+
doc.text
109+
})
110+
}
111+
}
112+
}
113+
114+
return Change(beforeRevision, afterRevision, fileStatus)
115+
}
116+
117+
}

0 commit comments

Comments
 (0)