Added option to discard hunks

This commit is contained in:
Abdelilah El Aissaoui 2022-06-19 19:52:53 +02:00
parent 1835ff748d
commit 15827d119a
5 changed files with 90 additions and 4 deletions

View File

@ -29,3 +29,14 @@ val String.dirPath: String
} else } else
this this
} }
val String.lineDelimiter: String?
get() {
return if (this.contains("\r\n"))
"\r\n"
else if (this.contains("\n"))
"\n"
else
null
}

View File

@ -20,6 +20,8 @@ import org.eclipse.jgit.lib.FileMode
import org.eclipse.jgit.lib.ObjectInserter import org.eclipse.jgit.lib.ObjectInserter
import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.lib.Repository
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.File
import java.io.FileWriter
import java.io.IOException import java.io.IOException
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.time.Instant import java.time.Instant
@ -145,6 +147,10 @@ class StatusManager @Inject constructor(
val content = rawFile.rawContent.toString(Charsets.UTF_8)//.removeSuffix(rawFile.lineDelimiter) val content = rawFile.rawContent.toString(Charsets.UTF_8)//.removeSuffix(rawFile.lineDelimiter)
val lineDelimiter: String? = rawFile.lineDelimiter val lineDelimiter: String? = rawFile.lineDelimiter
return getTextLines(content, lineDelimiter)
}
private fun getTextLines(content: String, lineDelimiter: String?): List<String> {
var splitted: List<String> = if (lineDelimiter != null) { var splitted: List<String> = if (lineDelimiter != null) {
content.split(lineDelimiter).toMutableList().apply { content.split(lineDelimiter).toMutableList().apply {
if (this.last() == "") if (this.last() == "")
@ -344,6 +350,52 @@ class StatusManager @Inject constructor(
addCommand.call() addCommand.call()
} }
} }
suspend fun resetHunk(git: Git, diffEntry: DiffEntry, hunk: Hunk) = withContext(Dispatchers.IO) {
val repository = git.repository
try {
val file = File(repository.directory.parent, diffEntry.oldPath)
val content = file.readText()
val textLines = getTextLines(content, content.lineDelimiter).toMutableList()
val hunkLines = hunk.lines.filter { it.lineType != LineType.CONTEXT }
val addedLines = hunkLines
.filter { it.lineType == LineType.ADDED }
.sortedBy { it.newLineNumber }
val removedLines = hunkLines
.filter { it.lineType == LineType.REMOVED }
.sortedBy { it.newLineNumber }
var linesRemoved = 0
// Start by removing the added lines to the index
for (line in addedLines) {
textLines.removeAt(line.newLineNumber + linesRemoved)
linesRemoved--
}
var linesAdded = 0
// Restore previously removed lines to the index
for (line in removedLines) {
// Check how many lines before this one have been deleted
val previouslyRemovedLines = addedLines.count { it.newLineNumber < line.newLineNumber }
textLines.add(line.newLineNumber + linesAdded - previouslyRemovedLines, line.text)
linesAdded++
}
val stagedFileText = textLines.joinToString("")
FileWriter(file).use { fw ->
fw.write(stagedFileText)
}
} catch (ex: Exception) {
throw Exception("Discard hunk failed. Check if the file still exists and has the write permissions set", ex)
}
}
} }

View File

@ -105,9 +105,13 @@ fun Diff(
onUnstageHunk = { entry, hunk -> onUnstageHunk = { entry, hunk ->
diffViewModel.unstageHunk(entry, hunk) diffViewModel.unstageHunk(entry, hunk)
}, },
) { entry, hunk -> onStageHunk = { entry, hunk ->
diffViewModel.stageHunk(entry, hunk) diffViewModel.stageHunk(entry, hunk)
} },
onResetHunk = { entry, hunk ->
diffViewModel.resetHunk(entry, hunk)
}
)
} else if (diffResult is DiffResult.NonText) { } else if (diffResult is DiffResult.NonText) {
NonTextDiff(diffResult) NonTextDiff(diffResult)
} }
@ -220,6 +224,7 @@ fun TextDiff(
diffResult: DiffResult.Text, diffResult: DiffResult.Text,
onUnstageHunk: (DiffEntry, Hunk) -> Unit, onUnstageHunk: (DiffEntry, Hunk) -> Unit,
onStageHunk: (DiffEntry, Hunk) -> Unit, onStageHunk: (DiffEntry, Hunk) -> Unit,
onResetHunk: (DiffEntry, Hunk) -> Unit,
) { ) {
val hunks = diffResult.hunks val hunks = diffResult.hunks
@ -237,6 +242,7 @@ fun TextDiff(
diffEntryType = diffEntryType, diffEntryType = diffEntryType,
onUnstageHunk = { onUnstageHunk(diffResult.diffEntry, hunk) }, onUnstageHunk = { onUnstageHunk(diffResult.diffEntry, hunk) },
onStageHunk = { onStageHunk(diffResult.diffEntry, hunk) }, onStageHunk = { onStageHunk(diffResult.diffEntry, hunk) },
onResetHunk = { onResetHunk(diffResult.diffEntry, hunk) },
) )
} }
} }
@ -261,6 +267,7 @@ fun HunkHeader(
diffEntryType: DiffEntryType, diffEntryType: DiffEntryType,
onUnstageHunk: () -> Unit, onUnstageHunk: () -> Unit,
onStageHunk: () -> Unit, onStageHunk: () -> Unit,
onResetHunk: () -> Unit,
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@ -293,6 +300,14 @@ fun HunkHeader(
color = MaterialTheme.colors.stageButton color = MaterialTheme.colors.stageButton
} }
if(diffEntryType is DiffEntryType.UnstagedDiff) {
SecondaryButton(
text = "Discard hunk",
backgroundButton = MaterialTheme.colors.error,
onClick = onResetHunk
)
}
SecondaryButton( SecondaryButton(
text = buttonText, text = buttonText,
backgroundButton = color, backgroundButton = color,

View File

@ -173,7 +173,8 @@ fun HistoryContentLoaded(
scrollState = scrollState, scrollState = scrollState,
diffResult = diffResult, diffResult = diffResult,
onUnstageHunk = { _, _ -> }, onUnstageHunk = { _, _ -> },
onStageHunk = { _, _ -> } onStageHunk = { _, _ -> },
onResetHunk = { _, _ -> },
) )
} else { } else {
Box( Box(

View File

@ -73,6 +73,13 @@ class DiffViewModel @Inject constructor(
statusManager.stageHunk(git, diffEntry, hunk) statusManager.stageHunk(git, diffEntry, hunk)
} }
fun resetHunk(diffEntry: DiffEntry, hunk: Hunk) = tabState.runOperation(
refreshType = RefreshType.UNCOMMITED_CHANGES,
showError = true,
) { git ->
statusManager.resetHunk(git, diffEntry, hunk)
}
fun unstageHunk(diffEntry: DiffEntry, hunk: Hunk) = tabState.runOperation( fun unstageHunk(diffEntry: DiffEntry, hunk: Hunk) = tabState.runOperation(
refreshType = RefreshType.UNCOMMITED_CHANGES, refreshType = RefreshType.UNCOMMITED_CHANGES,
) { git -> ) { git ->