From ff918a0643518a58850261dfce4873edd04d0084 Mon Sep 17 00:00:00 2001 From: Blarc Date: Tue, 28 Mar 2023 21:57:32 +0200 Subject: [PATCH] feat: Compute diff using `IdeaTextPatchBuilder` instead of `git diff`. This allows to compute diff only from files and **lines** selected in the commit dialog. --- CHANGELOG.md | 5 +- README.md | 6 ++- .../commits/intellij/plugin/AICommitAction.kt | 52 ++++++++++++------- .../commits/intellij/plugin/OpenAIService.kt | 2 +- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dde6e2..e046b55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 1457baa..11ea6db 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,11 @@
- [Description](#description) +- [Features](#features) - [Compatibility](#compatibility) - [Install](#install) - [Installation from zip](#installation-from-zip) -[//]: # (- [Features](#features)) [//]: # (- [Demo](#demo)) ## Description @@ -29,6 +29,10 @@ AI Commits is a plugin that generates your commit messages with AI. To get start install the plugin and set OpenAI private token in plugin's settings: Settings > Tools > AI Commits +## 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 diff --git a/src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/AICommitAction.kt b/src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/AICommitAction.kt index 0052f8f..04e6b10 100644 --- a/src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/AICommitAction.kt +++ b/src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/AICommitAction.kt @@ -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) @@ -45,30 +45,42 @@ class AICommitAction : AnAction(), DumbAware { } } } + private fun computeDiff( includedChanges: List, 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") } } \ No newline at end of file diff --git a/src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/OpenAIService.kt b/src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/OpenAIService.kt index 122fce2..a669865 100644 --- a/src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/OpenAIService.kt +++ b/src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/OpenAIService.kt @@ -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 {