Remove Kotlin interactive-add emulation and run patch add via the native Git runtime with PTY-backed session IO.
128 lines
5.5 KiB
Kotlin
128 lines
5.5 KiB
Kotlin
package solutions.tretter.githugandroid
|
|
|
|
import androidx.compose.runtime.saveable.listSaver
|
|
|
|
val RepoStateSaver = listSaver<RepoState, Any>(
|
|
save = { state ->
|
|
listOf(
|
|
state.initialized,
|
|
state.headBranch,
|
|
state.files.flatMap {
|
|
listOf(
|
|
it.name,
|
|
it.content,
|
|
it.staged.toString(),
|
|
it.tracked.toString(),
|
|
it.deleted.toString(),
|
|
it.stagedContent.orEmpty(),
|
|
)
|
|
},
|
|
state.commits.flatMap {
|
|
listOf(
|
|
it.id,
|
|
it.message,
|
|
it.authorTimestampSeconds?.toString().orEmpty(),
|
|
it.parentCount.toString(),
|
|
)
|
|
},
|
|
state.branches.flatMap { listOf(it.key, it.value.toString()) },
|
|
state.currentDir,
|
|
state.tags,
|
|
state.remotes.flatMap { listOf(it.key, it.value) },
|
|
state.config.flatMap { listOf(it.key, it.value) },
|
|
state.stashes,
|
|
state.fetchedBranches.toList(),
|
|
state.pushedBranches.toList(),
|
|
state.pushedTags.toList(),
|
|
state.submodules.flatMap { listOf(it.key, it.value) },
|
|
state.maintenanceActions.toList(),
|
|
state.fetchHeadCount,
|
|
emptyList<Any>(),
|
|
emptyList<Any>(),
|
|
)
|
|
},
|
|
restore = { saved ->
|
|
val initialized = saved[0] as Boolean
|
|
val headBranch = saved[1] as String
|
|
val fileParts = saved[2] as List<*>
|
|
val commitParts = saved[3] as List<*>
|
|
val branchParts = saved[4] as List<*>
|
|
val tags = saved[6] as List<*>
|
|
val remoteParts = saved[7] as List<*>
|
|
val configParts = saved.getOrNull(8) as? List<*> ?: emptyList<Any>()
|
|
val stashes = saved.getOrNull(9) as? List<*> ?: emptyList<Any>()
|
|
val fetchedBranches = saved.getOrNull(10) as? List<*> ?: emptyList<Any>()
|
|
val pushedBranches = saved.getOrNull(11) as? List<*> ?: emptyList<Any>()
|
|
val pushedTags = saved.getOrNull(12) as? List<*> ?: emptyList<Any>()
|
|
val submoduleParts = saved.getOrNull(13) as? List<*> ?: emptyList<Any>()
|
|
val maintenanceActions = saved.getOrNull(14) as? List<*> ?: emptyList<Any>()
|
|
val fetchHeadCount = saved.getOrNull(15) as? Int ?: 0
|
|
RepoState(
|
|
initialized = initialized,
|
|
headBranch = headBranch,
|
|
files = fileParts.chunked(
|
|
when {
|
|
fileParts.size % 6 == 0 -> 6
|
|
fileParts.size % 5 == 0 -> 5
|
|
else -> 4
|
|
},
|
|
).map {
|
|
GitFile(
|
|
name = it[0] as String,
|
|
content = it[1] as String,
|
|
staged = (it[2] as String).toBoolean(),
|
|
tracked = (it[3] as String).toBoolean(),
|
|
deleted = (it.getOrNull(4) as? String)?.toBoolean() ?: false,
|
|
stagedContent = (it.getOrNull(5) as? String)?.takeIf { value -> value.isNotEmpty() },
|
|
)
|
|
},
|
|
commits = commitParts.restoreCommitNodes(),
|
|
branches = branchParts.chunked(2).associate { (it[0] as String) to (it[1] as String).toInt() },
|
|
currentDir = saved[5] as String,
|
|
tags = tags.filterIsInstance<String>(),
|
|
remotes = remoteParts.chunked(2).associate { (it[0] as String) to (it[1] as String) },
|
|
config = configParts.chunked(2).associate { (it[0] as String) to (it[1] as String) },
|
|
stashes = stashes.filterIsInstance<String>(),
|
|
fetchedBranches = fetchedBranches.filterIsInstance<String>().toSet(),
|
|
fetchHeadCount = fetchHeadCount,
|
|
pushedBranches = pushedBranches.filterIsInstance<String>().toSet(),
|
|
pushedTags = pushedTags.filterIsInstance<String>().toSet(),
|
|
submodules = submoduleParts.chunked(2).associate { (it[0] as String) to (it[1] as String) },
|
|
maintenanceActions = maintenanceActions.filterIsInstance<String>().toSet(),
|
|
)
|
|
}
|
|
)
|
|
|
|
private fun List<*>.restoreCommitNodes(): List<CommitNode> {
|
|
val hasTimestampAndParentColumns = size % 4 == 0 && chunked(4).all { chunk ->
|
|
val timestamp = chunk.getOrNull(2) as? String
|
|
val parentCount = chunk.getOrNull(3) as? String
|
|
(timestamp.isNullOrEmpty() || timestamp.toLongOrNull()?.let { it >= 100_000_000L } == true) &&
|
|
parentCount?.toIntOrNull() != null
|
|
}
|
|
val hasTimestampColumn = !hasTimestampAndParentColumns && size % 3 == 0 && chunked(3).all { chunk ->
|
|
val timestamp = chunk.getOrNull(2) as? String
|
|
timestamp.isNullOrEmpty() || timestamp.toLongOrNull()?.let { it >= 100_000_000L } == true
|
|
}
|
|
val width = when {
|
|
hasTimestampAndParentColumns -> 4
|
|
hasTimestampColumn -> 3
|
|
else -> 2
|
|
}
|
|
|
|
return chunked(width).mapNotNull { chunk ->
|
|
val id = chunk.getOrNull(0) as? String ?: return@mapNotNull null
|
|
val message = chunk.getOrNull(1) as? String ?: ""
|
|
CommitNode(
|
|
id = id,
|
|
message = message,
|
|
authorTimestampSeconds = if (hasTimestampAndParentColumns || hasTimestampColumn) {
|
|
(chunk.getOrNull(2) as? String)?.toLongOrNull()
|
|
} else {
|
|
null
|
|
},
|
|
parentCount = if (hasTimestampAndParentColumns) (chunk.getOrNull(3) as? String)?.toIntOrNull() ?: 0 else 0,
|
|
)
|
|
}
|
|
}
|