Added lines numbers in diff view

This commit is contained in:
Abdelilah El Aissaoui 2022-01-05 02:52:32 +01:00
parent f20cfbb698
commit 1ed6572170
2 changed files with 196 additions and 100 deletions

View File

@ -2,7 +2,11 @@ package app.git.diff
data class Hunk(val header: String, val lines: List<Line>) data class Hunk(val header: String, val lines: List<Line>)
data class Line(val text: String, val oldLineNumber: Int, val newLineNumber: Int, val lineType: LineType) data class Line(val text: String, val oldLineNumber: Int, val newLineNumber: Int, val lineType: LineType) {
// lines numbers are stored based on 0 being the first one but on a file the first line is the 1, so increment it!
val displayOldLineNumber: Int = oldLineNumber + 1
val displayNewLineNumber: Int = newLineNumber + 1
}
enum class LineType { enum class LineType {
CONTEXT, CONTEXT,

View File

@ -2,7 +2,8 @@ package app.ui
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.ButtonDefaults import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
@ -16,12 +17,15 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import app.git.DiffEntryType import app.git.DiffEntryType
import app.git.diff.Hunk
import app.git.diff.Line
import app.git.diff.LineType import app.git.diff.LineType
import app.theme.primaryTextColor import app.theme.primaryTextColor
import app.ui.components.ScrollableLazyColumn import app.ui.components.ScrollableLazyColumn
import app.ui.components.SecondaryButton import app.ui.components.SecondaryButton
import app.viewmodels.DiffViewModel import app.viewmodels.DiffViewModel
import org.eclipse.jgit.diff.DiffEntry import org.eclipse.jgit.diff.DiffEntry
import kotlin.math.max
@Composable @Composable
fun Diff( fun Diff(
@ -41,36 +45,7 @@ fun Diff(
.background(MaterialTheme.colors.background) .background(MaterialTheme.colors.background)
.fillMaxSize() .fillMaxSize()
) { ) {
Row( DiffHeader(diffEntry, onCloseDiffView)
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
val filePath = if(diffEntry.newPath != "/dev/null")
diffEntry.newPath
else
diffEntry.oldPath
Text(
text = filePath,
color = MaterialTheme.colors.primaryTextColor,
fontSize = 16.sp,
modifier = Modifier.padding(horizontal = 16.dp),
)
Spacer(modifier = Modifier.weight(1f))
OutlinedButton(
modifier = Modifier
.padding(vertical = 8.dp, horizontal = 16.dp),
onClick = onCloseDiffView,
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.colors.background,
contentColor = MaterialTheme.colors.primary,
)
) {
Text("Close diff")
}
}
val scrollState by diffViewModel.lazyListState.collectAsState() val scrollState by diffViewModel.lazyListState.collectAsState()
ScrollableLazyColumn( ScrollableLazyColumn(
@ -78,14 +53,39 @@ fun Diff(
.fillMaxSize(), .fillMaxSize(),
state = scrollState state = scrollState
) { ) {
itemsIndexed(hunks) { index, hunk -> item { Spacer(modifier = Modifier.height(16.dp)) }
val hunksSeparation = if (index == 0) items(hunks) { hunk ->
0.dp HunkHeader(
else hunk = hunk,
16.dp diffEntryType = diffEntryType,
diffViewModel = diffViewModel,
)
SelectionContainer {
Column {
val oldHighestLineNumber = hunk.lines.maxOf { it.displayOldLineNumber }
val newHighestLineNumber = hunk.lines.maxOf { it.displayNewLineNumber }
val highestLineNumber = max(oldHighestLineNumber, newHighestLineNumber)
val highestLineNumberLength = highestLineNumber.toString().count()
hunk.lines.forEach { line ->
DiffLine(highestLineNumberLength, line)
}
}
}
}
}
}
}
@Composable
fun HunkHeader(
hunk: Hunk,
diffEntryType: DiffEntryType,
diffViewModel: DiffViewModel,
) {
Row( Row(
modifier = Modifier modifier = Modifier
.padding(top = hunksSeparation)
.background(MaterialTheme.colors.surface) .background(MaterialTheme.colors.surface)
.padding(vertical = 4.dp) .padding(vertical = 4.dp)
.fillMaxWidth() .fillMaxWidth()
@ -123,10 +123,44 @@ fun Diff(
) )
} }
} }
}
SelectionContainer { @Composable
Column { fun DiffHeader(diffEntry: DiffEntry, onCloseDiffView: () -> Unit) {
hunk.lines.forEach { line -> Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
val filePath = if(diffEntry.newPath != "/dev/null")
diffEntry.newPath
else
diffEntry.oldPath
Text(
text = filePath,
color = MaterialTheme.colors.primaryTextColor,
fontSize = 16.sp,
modifier = Modifier.padding(horizontal = 16.dp),
)
Spacer(modifier = Modifier.weight(1f))
OutlinedButton(
modifier = Modifier
.padding(vertical = 8.dp, horizontal = 16.dp),
onClick = onCloseDiffView,
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.colors.background,
contentColor = MaterialTheme.colors.primary,
)
) {
Text("Close diff")
}
}
}
@Composable
fun DiffLine(highestLineNumberLength: Int, line: Line) {
val backgroundColor = when (line.lineType) { val backgroundColor = when (line.lineType) {
LineType.ADDED -> { LineType.ADDED -> {
Color(0x77a9d49b) Color(0x77a9d49b)
@ -138,12 +172,34 @@ fun Diff(
MaterialTheme.colors.background MaterialTheme.colors.background
} }
} }
Row (
modifier = Modifier
.background(backgroundColor)
) {
val oldLineText = if(line.lineType == LineType.REMOVED || line.lineType == LineType.CONTEXT) {
formattedLineNumber(line.displayOldLineNumber, highestLineNumberLength)
} else
emptyLineNumber(highestLineNumberLength)
val newLineText = if(line.lineType == LineType.ADDED || line.lineType == LineType.CONTEXT) {
formattedLineNumber(line.displayNewLineNumber, highestLineNumberLength)
} else
emptyLineNumber(highestLineNumberLength)
DisableSelection {
LineNumber(
text = oldLineText,
)
LineNumber(
text = newLineText
)
}
Text( Text(
text = line.text, text = line.text,
modifier = Modifier modifier = Modifier
.background(backgroundColor) .padding(start = 8.dp)
.padding(start = 16.dp)
.fillMaxWidth(), .fillMaxWidth(),
color = MaterialTheme.colors.primaryTextColor, color = MaterialTheme.colors.primaryTextColor,
maxLines = 1, maxLines = 1,
@ -152,9 +208,45 @@ fun Diff(
) )
} }
} }
@Composable
fun LineNumber(text: String) {
Text(
text = text,
color = MaterialTheme.colors.primaryTextColor,
modifier = Modifier
.background(MaterialTheme.colors.surface)
.padding(horizontal = 4.dp),
fontFamily = FontFamily.Monospace,
fontSize = 14.sp,
)
} }
fun formattedLineNumber(number: Int, charactersCount: Int): String {
val numberStr = number.toString()
return if(numberStr.count() == charactersCount)
numberStr
else {
val lengthDiff = charactersCount - numberStr.count()
val numberBuilder = StringBuilder()
// Add whitespaces before the numbers
repeat(lengthDiff) {
numberBuilder.append(" ")
} }
} numberBuilder.append(numberStr)
numberBuilder.toString()
} }
} }
fun emptyLineNumber(charactersCount: Int): String {
val numberBuilder = StringBuilder()
// Add whitespaces before the numbers
repeat(charactersCount) {
numberBuilder.append(" ")
}
return numberBuilder.toString()
}