Skip to content

Commit

Permalink
feat: Compute diff using IdeaTextPatchBuilder instead of git diff.
Browse files Browse the repository at this point in the history
This allows to compute diff only from files and **lines** selected in the commit dialog.
  • Loading branch information
Blarc committed Mar 28, 2023
1 parent 5e8bc5f commit ff918a0
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 25 deletions.
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
## [Unreleased]
### Added
- Show notification when diff is empty.

### Fixed
- Use `--cached` flag for computing git diff.
- Compute diff using `IdeaTextPatchBuilder` instead of `git diff`.
- This allows to compute diff only from files and **lines** selected in the commit dialog.

## [0.2.0] - 2023-03-27

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,22 @@
<br>

- [Description](#description)
- [Features](#features)
- [Compatibility](#compatibility)
- [Install](#install)
- [Installation from zip](#installation-from-zip)

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

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

## Features
- Generate commit message from diff using OpenAI API
- Compute diff only from the selected files and lines in the commit dialog

## Compatibility
IntelliJ IDEA, PhpStorm, WebStorm, PyCharm, RubyMine, AppCode, CLion, GoLand, DataGrip, Rider, MPS, Android Studio, DataSpell, Code With Me

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ import com.github.blarc.ai.commits.intellij.plugin.notifications.Notification
import com.github.blarc.ai.commits.intellij.plugin.notifications.sendNotification
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.diff.impl.patch.IdeaTextPatchBuilder
import com.intellij.openapi.diff.impl.patch.UnifiedDiffWriter
import com.intellij.openapi.progress.runBackgroundableTask
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.vcs.VcsDataKeys
import com.intellij.openapi.vcs.changes.Change
import com.intellij.vcs.commit.AbstractCommitWorkflowHandler
import git4idea.commands.Git
import git4idea.commands.GitCommand
import git4idea.commands.GitLineHandler
import git4idea.repo.GitRepositoryManager
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.StringWriter

class AICommitAction : AnAction(), DumbAware {
@OptIn(DelicateCoroutinesApi::class)
Expand All @@ -45,30 +45,42 @@ class AICommitAction : AnAction(), DumbAware {
}
}
}

private fun computeDiff(
includedChanges: List<Change>,
project: Project
): String {
val diff = includedChanges.joinToString("\n") {

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

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

val diffCommand = GitLineHandler(
project,
repository.root,
GitCommand.DIFF
)
diffCommand.addParameters("--cached")
diffCommand.addParameters(file.path)

val commandResult = Git.getInstance().runCommand(diffCommand)
commandResult.outputAsJoinedString
}
return diff
// compute diff for each repository
return changesByRepository
.map { (repository, changes) ->
repository?.let {
val filePatches = IdeaTextPatchBuilder.buildPatch(
project,
changes,
repository.root.toNioPath(), false, true
)

val stringWriter = StringWriter()
stringWriter.write("Repository: ${repository.root.path}\n")
UnifiedDiffWriter.write(project, filePatches, stringWriter, "\n", null)
stringWriter.toString()
}
}
.joinToString("\n")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class OpenAIService {
}

private fun getPrompt(locale: String, diff: String) =
"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}"
"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}"

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

0 comments on commit ff918a0

Please sign in to comment.