From 67aff36bc4a2e40fd1770a709da72a7f0db1da48 Mon Sep 17 00:00:00 2001 From: Abdelilah El Aissaoui Date: Mon, 6 Jun 2022 00:49:02 +0200 Subject: [PATCH] Added persistance of commit message Merge message is also recovered when having conflicts --- src/main/kotlin/app/ui/Diff.kt | 2 +- src/main/kotlin/app/ui/UncommitedChanges.kt | 29 +++++--- .../kotlin/app/viewmodels/StatusViewModel.kt | 67 ++++++++++++++++++- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/app/ui/Diff.kt b/src/main/kotlin/app/ui/Diff.kt index 348d99b..36fbb1e 100644 --- a/src/main/kotlin/app/ui/Diff.kt +++ b/src/main/kotlin/app/ui/Diff.kt @@ -404,7 +404,7 @@ fun DiffLine( } 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 .padding(start = 8.dp) .fillMaxSize(), diff --git a/src/main/kotlin/app/ui/UncommitedChanges.kt b/src/main/kotlin/app/ui/UncommitedChanges.kt index 71dff53..d39654e 100644 --- a/src/main/kotlin/app/ui/UncommitedChanges.kt +++ b/src/main/kotlin/app/ui/UncommitedChanges.kt @@ -40,6 +40,7 @@ import app.ui.components.SecondaryButton import app.ui.context_menu.* import app.viewmodels.StageStatus import app.viewmodels.StatusViewModel +import kotlinx.coroutines.flow.collect import org.eclipse.jgit.lib.RepositoryState @Composable @@ -53,7 +54,7 @@ fun UncommitedChanges( onHistoryFile: (String) -> Unit, ) { 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 staged: List @@ -70,13 +71,18 @@ fun UncommitedChanges( val doCommit = { amend: Boolean -> statusViewModel.commit(commitMessage, amend) onStagedDiffEntrySelected(null) - statusViewModel.savedCommitMessage = "" commitMessage = "" } val canCommit = commitMessage.isNotEmpty() && staged.isNotEmpty() val canAmend = (commitMessage.isNotEmpty() || staged.isNotEmpty()) && statusViewModel.hasPreviousCommits + LaunchedEffect(Unit) { + statusViewModel.commitMessageChangesFlow.collect { newCommitMessage -> + commitMessage = newCommitMessage + } + } + Column { AnimatedVisibility( visible = stageStatus is StageStatus.Loading, @@ -94,7 +100,7 @@ fun UncommitedChanges( title = "Staged", allActionTitle = "Unstage all", actionTitle = "Unstage", - selectedEntryType = if(selectedEntryType is DiffEntryType.StagedDiff) selectedEntryType else null, + selectedEntryType = if (selectedEntryType is DiffEntryType.StagedDiff) selectedEntryType else null, actionColor = MaterialTheme.colors.unstageButton, statusEntries = staged, onDiffEntrySelected = onStagedDiffEntrySelected, @@ -122,7 +128,7 @@ fun UncommitedChanges( .fillMaxWidth(), title = "Unstaged", actionTitle = "Stage", - selectedEntryType = if(selectedEntryType is DiffEntryType.UnstagedDiff) selectedEntryType else null, + selectedEntryType = if (selectedEntryType is DiffEntryType.UnstagedDiff) selectedEntryType else null, actionColor = MaterialTheme.colors.stageButton, statusEntries = unstaged, onDiffEntrySelected = onUnstagedDiffEntrySelected, @@ -175,7 +181,8 @@ fun UncommitedChanges( value = commitMessage, onValueChange = { commitMessage = it - statusViewModel.savedCommitMessage = it + + statusViewModel.updateCommitMessage(it) }, label = { Text("Write your commit message here", fontSize = 14.sp) }, colors = textFieldColors(), @@ -185,13 +192,19 @@ fun UncommitedChanges( when { repositoryState.isMerging -> MergeButtons( haveConflictsBeenSolved = unstaged.isEmpty(), - onAbort = { statusViewModel.abortMerge() }, + onAbort = { + statusViewModel.abortMerge() + statusViewModel.updateCommitMessage("") + }, onMerge = { doCommit(false) } ) repositoryState.isRebasing -> RebasingButtons( canContinue = staged.isNotEmpty() || unstaged.isNotEmpty(), haveConflictsBeenSolved = unstaged.isEmpty(), - onAbort = { statusViewModel.abortRebase() }, + onAbort = { + statusViewModel.abortRebase() + statusViewModel.updateCommitMessage("") + }, onContinue = { statusViewModel.continueRebase() }, onSkip = { statusViewModel.skipRebase() }, ) @@ -502,7 +515,7 @@ private fun FileEntry( tint = statusEntry.iconColor, ) - if(statusEntry.parentDirectoryPath.isNotEmpty()) { + if (statusEntry.parentDirectoryPath.isNotEmpty()) { Text( text = statusEntry.parentDirectoryPath, modifier = Modifier.weight(1f, fill = false), diff --git a/src/main/kotlin/app/viewmodels/StatusViewModel.kt b/src/main/kotlin/app/viewmodels/StatusViewModel.kt index 7120e68..067ca3e 100644 --- a/src/main/kotlin/app/viewmodels/StatusViewModel.kt +++ b/src/main/kotlin/app/viewmodels/StatusViewModel.kt @@ -1,19 +1,21 @@ package app.viewmodels +import app.extensions.isMerging import app.git.* import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.withContext import org.eclipse.jgit.api.Git +import org.eclipse.jgit.lib.RepositoryState import java.io.File import javax.inject.Inject class StatusViewModel @Inject constructor( private val tabState: TabState, private val statusManager: StatusManager, - private val branchesManager: BranchesManager, - private val repositoryManager: RepositoryManager, private val rebaseManager: RebaseManager, private val mergeManager: MergeManager, private val logManager: LogManager, @@ -21,11 +23,32 @@ class StatusViewModel @Inject constructor( private val _stageStatus = MutableStateFlow(StageStatus.Loaded(listOf(), listOf())) val stageStatus: StateFlow = _stageStatus - var savedCommitMessage: String = "" + var savedCommitMessage = CommitMessage("", MessageType.NORMAL) + var hasPreviousCommits = true // When false, disable "amend previous commit" private var lastUncommitedChangesState = false + /** + * Notify the UI that the commit message has been changed by the view model + */ + private val _commitMessageChangesFlow = MutableSharedFlow() + val commitMessageChangesFlow: SharedFlow = _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( refreshType = RefreshType.UNCOMMITED_CHANGES, ) { git -> @@ -66,6 +89,21 @@ class StatusViewModel @Inject constructor( private suspend fun loadStatus(git: Git) { 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 { _stageStatus.value = StageStatus.Loading 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) { lastUncommitedChangesState = statusManager.hasUncommitedChanges(git) } @@ -92,6 +141,7 @@ class StatusViewModel @Inject constructor( message statusManager.commit(git, commitMessage, amend) + updateCommitMessage("") } suspend fun refresh(git: Git) = withContext(Dispatchers.IO) { @@ -148,6 +198,11 @@ class StatusViewModel @Inject constructor( fileToDelete.delete() } + + fun updateCommitMessage(message: String) { + savedCommitMessage = savedCommitMessage.copy(message = message) + persistMessage() + } } sealed class StageStatus { @@ -155,3 +210,9 @@ sealed class StageStatus { data class Loaded(val staged: List, val unstaged: List) : StageStatus() } +data class CommitMessage(val message: String, val messageType: MessageType) + +enum class MessageType { + NORMAL, + MERGE; +} \ No newline at end of file