Skip to content

Commit ff918a0

Browse files
committed
feat: Compute diff using IdeaTextPatchBuilder instead of git diff.
This allows to compute diff only from files and **lines** selected in the commit dialog.
1 parent 5e8bc5f commit ff918a0

File tree

4 files changed

+40
-25
lines changed

4 files changed

+40
-25
lines changed

CHANGELOG.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
## [Unreleased]
44
### Added
55
- Show notification when diff is empty.
6-
7-
### Fixed
8-
- Use `--cached` flag for computing git diff.
6+
- Compute diff using `IdeaTextPatchBuilder` instead of `git diff`.
7+
- This allows to compute diff only from files and **lines** selected in the commit dialog.
98

109
## [0.2.0] - 2023-03-27
1110

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,22 @@
1717
<br>
1818

1919
- [Description](#description)
20+
- [Features](#features)
2021
- [Compatibility](#compatibility)
2122
- [Install](#install)
2223
- [Installation from zip](#installation-from-zip)
2324

24-
[//]: # (- [Features]&#40;#features&#41;)
2525
[//]: # (- [Demo]&#40;#demo&#41;)
2626

2727
## Description
2828
AI Commits is a plugin that generates your commit messages with AI. To get started,
2929
install the plugin and set OpenAI private token in plugin's settings:
3030
<kbd>Settings</kbd> > <kbd>Tools</kbd> > <kbd>AI Commits</kbd>
3131

32+
## Features
33+
- Generate commit message from diff using OpenAI API
34+
- Compute diff only from the selected files and lines in the commit dialog
35+
3236
## Compatibility
3337
IntelliJ IDEA, PhpStorm, WebStorm, PyCharm, RubyMine, AppCode, CLion, GoLand, DataGrip, Rider, MPS, Android Studio, DataSpell, Code With Me
3438

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

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@ import com.github.blarc.ai.commits.intellij.plugin.notifications.Notification
55
import com.github.blarc.ai.commits.intellij.plugin.notifications.sendNotification
66
import com.intellij.openapi.actionSystem.AnAction
77
import com.intellij.openapi.actionSystem.AnActionEvent
8+
import com.intellij.openapi.diff.impl.patch.IdeaTextPatchBuilder
9+
import com.intellij.openapi.diff.impl.patch.UnifiedDiffWriter
810
import com.intellij.openapi.progress.runBackgroundableTask
911
import com.intellij.openapi.project.DumbAware
1012
import com.intellij.openapi.project.Project
1113
import com.intellij.openapi.vcs.VcsDataKeys
1214
import com.intellij.openapi.vcs.changes.Change
1315
import com.intellij.vcs.commit.AbstractCommitWorkflowHandler
14-
import git4idea.commands.Git
15-
import git4idea.commands.GitCommand
16-
import git4idea.commands.GitLineHandler
1716
import git4idea.repo.GitRepositoryManager
1817
import kotlinx.coroutines.DelicateCoroutinesApi
1918
import kotlinx.coroutines.Dispatchers
2019
import kotlinx.coroutines.GlobalScope
2120
import kotlinx.coroutines.launch
21+
import java.io.StringWriter
2222

2323
class AICommitAction : AnAction(), DumbAware {
2424
@OptIn(DelicateCoroutinesApi::class)
@@ -45,30 +45,42 @@ class AICommitAction : AnAction(), DumbAware {
4545
}
4646
}
4747
}
48+
4849
private fun computeDiff(
4950
includedChanges: List<Change>,
5051
project: Project
5152
): String {
52-
val diff = includedChanges.joinToString("\n") {
5353

54-
// Try to get the virtual file for the change and return an empty string if it doesn't exist
55-
val file = it.virtualFile ?: return@joinToString ""
54+
val gitRepositoryManager = GitRepositoryManager.getInstance(project)
5655

57-
// Try to get the git repository for the file and return an empty string if it doesn't exist
58-
val repository = GitRepositoryManager.getInstance(project).getRepositoryForFile(file)
59-
?: return@joinToString ""
56+
// go through included changes, create a map of repository to changes and discard nulls
57+
val changesByRepository = includedChanges
58+
.mapNotNull { change ->
59+
change.virtualFile?.let { file ->
60+
gitRepositoryManager.getRepositoryForFileQuick(
61+
file
62+
) to change
63+
}
64+
}
65+
.groupBy({ it.first }, { it.second })
6066

61-
val diffCommand = GitLineHandler(
62-
project,
63-
repository.root,
64-
GitCommand.DIFF
65-
)
66-
diffCommand.addParameters("--cached")
67-
diffCommand.addParameters(file.path)
6867

69-
val commandResult = Git.getInstance().runCommand(diffCommand)
70-
commandResult.outputAsJoinedString
71-
}
72-
return diff
68+
// compute diff for each repository
69+
return changesByRepository
70+
.map { (repository, changes) ->
71+
repository?.let {
72+
val filePatches = IdeaTextPatchBuilder.buildPatch(
73+
project,
74+
changes,
75+
repository.root.toNioPath(), false, true
76+
)
77+
78+
val stringWriter = StringWriter()
79+
stringWriter.write("Repository: ${repository.root.path}\n")
80+
UnifiedDiffWriter.write(project, filePatches, stringWriter, "\n", null)
81+
stringWriter.toString()
82+
}
83+
}
84+
.joinToString("\n")
7385
}
7486
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class OpenAIService {
2020
}
2121

2222
private fun getPrompt(locale: String, diff: String) =
23-
"Write an insightful but concise Git commit message in a complete sentence in present tense for the following diff without prefacing it with anything, the response must be in the language ${locale}:\\n${diff}"
23+
"Write an insightful but concise Git commit message in a complete sentence in present tense for the following diff without prefacing it with anything, the response must be in the language ${locale}. The following text are the differences between files, where deleted lines are prefixed with a single minus sign and added lines are prefixed with a single plus sign:\\n${diff}"
2424

2525
@OptIn(BetaOpenAI::class)
2626
suspend fun generateCommitMessage(diff: String, completions: Int): String {

0 commit comments

Comments
 (0)