Added persistance of commit message

Merge message is also recovered when having conflicts
This commit is contained in:
Abdelilah El Aissaoui 2022-06-06 00:49:02 +02:00
parent 7335499f97
commit 67aff36bc4
3 changed files with 86 additions and 12 deletions

View File

@ -404,7 +404,7 @@ fun DiffLine(
} }
Text( Text(
text = line.text.replace("\t", " "), // this replace is a workaround until this issue gets fixed https://github.com/JetBrains/compose-jb/issues/615 text = line.text.replace("\t", " "), // TODO this replace is a workaround until this issue gets fixed https://github.com/JetBrains/compose-jb/issues/615
modifier = Modifier modifier = Modifier
.padding(start = 8.dp) .padding(start = 8.dp)
.fillMaxSize(), .fillMaxSize(),

View File

@ -40,6 +40,7 @@ import app.ui.components.SecondaryButton
import app.ui.context_menu.* import app.ui.context_menu.*
import app.viewmodels.StageStatus import app.viewmodels.StageStatus
import app.viewmodels.StatusViewModel import app.viewmodels.StatusViewModel
import kotlinx.coroutines.flow.collect
import org.eclipse.jgit.lib.RepositoryState import org.eclipse.jgit.lib.RepositoryState
@Composable @Composable
@ -53,7 +54,7 @@ fun UncommitedChanges(
onHistoryFile: (String) -> Unit, onHistoryFile: (String) -> Unit,
) { ) {
val stageStatusState = statusViewModel.stageStatus.collectAsState() val stageStatusState = statusViewModel.stageStatus.collectAsState()
var commitMessage by remember { mutableStateOf(statusViewModel.savedCommitMessage) } var commitMessage by remember { mutableStateOf(statusViewModel.savedCommitMessage.message) }
val stageStatus = stageStatusState.value val stageStatus = stageStatusState.value
val staged: List<StatusEntry> val staged: List<StatusEntry>
@ -70,13 +71,18 @@ fun UncommitedChanges(
val doCommit = { amend: Boolean -> val doCommit = { amend: Boolean ->
statusViewModel.commit(commitMessage, amend) statusViewModel.commit(commitMessage, amend)
onStagedDiffEntrySelected(null) onStagedDiffEntrySelected(null)
statusViewModel.savedCommitMessage = ""
commitMessage = "" commitMessage = ""
} }
val canCommit = commitMessage.isNotEmpty() && staged.isNotEmpty() val canCommit = commitMessage.isNotEmpty() && staged.isNotEmpty()
val canAmend = (commitMessage.isNotEmpty() || staged.isNotEmpty()) && statusViewModel.hasPreviousCommits val canAmend = (commitMessage.isNotEmpty() || staged.isNotEmpty()) && statusViewModel.hasPreviousCommits
LaunchedEffect(Unit) {
statusViewModel.commitMessageChangesFlow.collect { newCommitMessage ->
commitMessage = newCommitMessage
}
}
Column { Column {
AnimatedVisibility( AnimatedVisibility(
visible = stageStatus is StageStatus.Loading, visible = stageStatus is StageStatus.Loading,
@ -175,7 +181,8 @@ fun UncommitedChanges(
value = commitMessage, value = commitMessage,
onValueChange = { onValueChange = {
commitMessage = it commitMessage = it
statusViewModel.savedCommitMessage = it
statusViewModel.updateCommitMessage(it)
}, },
label = { Text("Write your commit message here", fontSize = 14.sp) }, label = { Text("Write your commit message here", fontSize = 14.sp) },
colors = textFieldColors(), colors = textFieldColors(),
@ -185,13 +192,19 @@ fun UncommitedChanges(
when { when {
repositoryState.isMerging -> MergeButtons( repositoryState.isMerging -> MergeButtons(
haveConflictsBeenSolved = unstaged.isEmpty(), haveConflictsBeenSolved = unstaged.isEmpty(),
onAbort = { statusViewModel.abortMerge() }, onAbort = {
statusViewModel.abortMerge()
statusViewModel.updateCommitMessage("")
},
onMerge = { doCommit(false) } onMerge = { doCommit(false) }
) )
repositoryState.isRebasing -> RebasingButtons( repositoryState.isRebasing -> RebasingButtons(
canContinue = staged.isNotEmpty() || unstaged.isNotEmpty(), canContinue = staged.isNotEmpty() || unstaged.isNotEmpty(),
haveConflictsBeenSolved = unstaged.isEmpty(), haveConflictsBeenSolved = unstaged.isEmpty(),
onAbort = { statusViewModel.abortRebase() }, onAbort = {
statusViewModel.abortRebase()
statusViewModel.updateCommitMessage("")
},
onContinue = { statusViewModel.continueRebase() }, onContinue = { statusViewModel.continueRebase() },
onSkip = { statusViewModel.skipRebase() }, onSkip = { statusViewModel.skipRebase() },
) )

View File

@ -1,19 +1,21 @@
package app.viewmodels package app.viewmodels
import app.extensions.isMerging
import app.git.* import app.git.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.RepositoryState
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
class StatusViewModel @Inject constructor( class StatusViewModel @Inject constructor(
private val tabState: TabState, private val tabState: TabState,
private val statusManager: StatusManager, private val statusManager: StatusManager,
private val branchesManager: BranchesManager,
private val repositoryManager: RepositoryManager,
private val rebaseManager: RebaseManager, private val rebaseManager: RebaseManager,
private val mergeManager: MergeManager, private val mergeManager: MergeManager,
private val logManager: LogManager, private val logManager: LogManager,
@ -21,11 +23,32 @@ class StatusViewModel @Inject constructor(
private val _stageStatus = MutableStateFlow<StageStatus>(StageStatus.Loaded(listOf(), listOf())) private val _stageStatus = MutableStateFlow<StageStatus>(StageStatus.Loaded(listOf(), listOf()))
val stageStatus: StateFlow<StageStatus> = _stageStatus val stageStatus: StateFlow<StageStatus> = _stageStatus
var savedCommitMessage: String = "" var savedCommitMessage = CommitMessage("", MessageType.NORMAL)
var hasPreviousCommits = true // When false, disable "amend previous commit" var hasPreviousCommits = true // When false, disable "amend previous commit"
private var lastUncommitedChangesState = false private var lastUncommitedChangesState = false
/**
* Notify the UI that the commit message has been changed by the view model
*/
private val _commitMessageChangesFlow = MutableSharedFlow<String>()
val commitMessageChangesFlow: SharedFlow<String> = _commitMessageChangesFlow
private fun persistMessage() = tabState.runOperation(
refreshType = RefreshType.NONE,
) { git ->
val messageToPersist = savedCommitMessage.message.ifBlank { null }
println("Persisting message: $messageToPersist")
if (git.repository.repositoryState.isMerging) {
git.repository.writeMergeCommitMsg(messageToPersist)
} else if (git.repository.repositoryState == RepositoryState.SAFE) {
git.repository.writeCommitEditMsg(messageToPersist)
}
}
fun stage(statusEntry: StatusEntry) = tabState.runOperation( fun stage(statusEntry: StatusEntry) = tabState.runOperation(
refreshType = RefreshType.UNCOMMITED_CHANGES, refreshType = RefreshType.UNCOMMITED_CHANGES,
) { git -> ) { git ->
@ -66,6 +89,21 @@ class StatusViewModel @Inject constructor(
private suspend fun loadStatus(git: Git) { private suspend fun loadStatus(git: Git) {
val previousStatus = _stageStatus.value val previousStatus = _stageStatus.value
val requiredMessageType = if (git.repository.repositoryState == RepositoryState.MERGING) {
MessageType.MERGE
} else {
MessageType.NORMAL
}
if (requiredMessageType != savedCommitMessage.messageType) {
savedCommitMessage = CommitMessage(messageByRepoState(git), requiredMessageType)
_commitMessageChangesFlow.emit(savedCommitMessage.message)
} else if (savedCommitMessage.message.isEmpty()) {
savedCommitMessage = savedCommitMessage.copy(message = messageByRepoState(git))
_commitMessageChangesFlow.emit(savedCommitMessage.message)
}
try { try {
_stageStatus.value = StageStatus.Loading _stageStatus.value = StageStatus.Loading
val status = statusManager.getStatus(git) val status = statusManager.getStatus(git)
@ -79,6 +117,17 @@ class StatusViewModel @Inject constructor(
} }
} }
private fun messageByRepoState(git: Git): String {
val message: String? = if (git.repository.repositoryState == RepositoryState.MERGING) {
git.repository.readMergeCommitMsg()
} else {
git.repository.readCommitEditMsg()
}
//TODO this replace is a workaround until this issue gets fixed https://github.com/JetBrains/compose-jb/issues/615
return message.orEmpty().replace("\t", " ")
}
private suspend fun loadHasUncommitedChanges(git: Git) = withContext(Dispatchers.IO) { private suspend fun loadHasUncommitedChanges(git: Git) = withContext(Dispatchers.IO) {
lastUncommitedChangesState = statusManager.hasUncommitedChanges(git) lastUncommitedChangesState = statusManager.hasUncommitedChanges(git)
} }
@ -92,6 +141,7 @@ class StatusViewModel @Inject constructor(
message message
statusManager.commit(git, commitMessage, amend) statusManager.commit(git, commitMessage, amend)
updateCommitMessage("")
} }
suspend fun refresh(git: Git) = withContext(Dispatchers.IO) { suspend fun refresh(git: Git) = withContext(Dispatchers.IO) {
@ -148,6 +198,11 @@ class StatusViewModel @Inject constructor(
fileToDelete.delete() fileToDelete.delete()
} }
fun updateCommitMessage(message: String) {
savedCommitMessage = savedCommitMessage.copy(message = message)
persistMessage()
}
} }
sealed class StageStatus { sealed class StageStatus {
@ -155,3 +210,9 @@ sealed class StageStatus {
data class Loaded(val staged: List<StatusEntry>, val unstaged: List<StatusEntry>) : StageStatus() data class Loaded(val staged: List<StatusEntry>, val unstaged: List<StatusEntry>) : StageStatus()
} }
data class CommitMessage(val message: String, val messageType: MessageType)
enum class MessageType {
NORMAL,
MERGE;
}