Improved git diff performance by using coroutines

This commit is contained in:
Abdelilah El Aissaoui 2021-09-30 18:02:34 +02:00
parent 54092ba112
commit fe915f68d1
3 changed files with 53 additions and 31 deletions

View file

@ -5,9 +5,13 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -19,10 +23,13 @@ import theme.primaryTextColor
@Composable
fun Diff(gitManager: GitManager, diffEntryType: DiffEntryType, onCloseDiffView: () -> Unit) {
val text = remember(diffEntryType.diffEntry) {
gitManager.diffFormat(diffEntryType)
var text by remember { mutableStateOf(listOf<String>()) }
LaunchedEffect(diffEntryType.diffEntry) {
text = gitManager.diffFormat(diffEntryType)
}
Card(
modifier = Modifier
.padding(8.dp)

View file

@ -1,10 +1,7 @@
import git.*
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.diff.DiffEntry
import org.eclipse.jgit.diff.DiffFormatter
@ -24,6 +21,7 @@ class GitManager {
private val remoteOperationsManager = RemoteOperationsManager()
private val branchesManager = BranchesManager()
private val stashManager = StashManager()
private val diffManager = DiffManager()
private val managerScope = CoroutineScope(SupervisorJob())
@ -126,31 +124,8 @@ class GitManager {
val hasUncommitedChanges: StateFlow<Boolean>
get() = statusManager.hasUncommitedChanges
fun diffFormat(diffEntryType: DiffEntryType): List<String> {
val diffEntry = diffEntryType.diffEntry
val byteArrayOutputStream = ByteArrayOutputStream()
DiffFormatter(byteArrayOutputStream).use { formatter ->
val repo = safeGit.repository
formatter.setRepository(repo)
val oldTree = DirCacheIterator(repo.readDirCache())
val newTree = FileTreeIterator(repo)
if (diffEntryType is DiffEntryType.UnstagedDiff)
formatter.scan(oldTree, newTree)
formatter.format(diffEntry)
formatter.flush()
}
val diff = byteArrayOutputStream.toString(Charsets.UTF_8)
// TODO This is just a workaround, try to find properly which lines have to be displayed by using a custom diff
return diff.split("\n", "\r\n").filterNot {
it.startsWith("diff --git")
}
suspend fun diffFormat(diffEntryType: DiffEntryType): List<String> {
return diffManager.diffFormat(safeGit, diffEntryType)
}
fun pull() = managerScope.launch {

View file

@ -0,0 +1,40 @@
package git
import DiffEntryType
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.diff.DiffFormatter
import org.eclipse.jgit.dircache.DirCacheIterator
import org.eclipse.jgit.treewalk.FileTreeIterator
import java.io.ByteArrayOutputStream
class DiffManager {
suspend fun diffFormat(git: Git, diffEntryType: DiffEntryType): List<String> = withContext(Dispatchers.IO) {
val diffEntry = diffEntryType.diffEntry
val byteArrayOutputStream = ByteArrayOutputStream()
DiffFormatter(byteArrayOutputStream).use { formatter ->
val repo = git.repository
formatter.setRepository(repo)
val oldTree = DirCacheIterator(repo.readDirCache())
val newTree = FileTreeIterator(repo)
if (diffEntryType is DiffEntryType.UnstagedDiff)
formatter.scan(oldTree, newTree)
formatter.format(diffEntry)
formatter.flush()
}
val diff = byteArrayOutputStream.toString(Charsets.UTF_8)
// TODO This is just a workaround, try to find properly which lines have to be displayed by using a custom diff
return@withContext diff.split("\n", "\r\n").filterNot {
it.startsWith("diff --git")
}
}
}