Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/composeResources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
<string name="menu_pop_stash_tooltip">Pop the last stash</string>
<string name="menu_terminal">Terminal</string>
<string name="menu_terminal_tooltip">Open a terminal in the repository's path</string>
<string name="menu_editor">Editor</string>
<string name="menu_editor_tooltip">Open a repository in external editor</string>
<string name="menu_actions">Actions</string>
<string name="menu_actions_tooltip">Additional actions</string>
<string name="menu_settings">Settings</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.jetpackduba.gitnuro.editor

import com.jetpackduba.gitnuro.managers.ErrorsManager
import com.jetpackduba.gitnuro.managers.IShellManager
import com.jetpackduba.gitnuro.models.errorNotification
import com.jetpackduba.gitnuro.repositories.AppSettingsRepository
import javax.inject.Inject

/**
* Use-case for opening the repository directory with an external editor.
*/
class OpenRepositoryInEditorUseCase @Inject constructor(
private val settings: AppSettingsRepository,
private val shellManager: IShellManager,
private val errorsManager: ErrorsManager
) {
/**
* Opens the given path in the configured external editor.
* @param path The path to open. Should be a directory.
*/
suspend operator fun invoke(path: String) {
val editor = settings.editor;
val isSet = editor.isNotEmpty();

if (!isSet) {
errorsManager.emitNotification(
errorNotification("No editor configured")
)
return
}

shellManager.runCommandInPath(listOf(editor, path), path)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ enum class KeybindingOption {
* Used to open the settings screen
*/
SETTINGS,

/**
* Used to open the current repository in an external editor
*/
OPEN_EDITOR
}


Expand Down Expand Up @@ -156,6 +161,9 @@ private fun baseKeybindings() = mapOf(
KeybindingOption.SETTINGS to listOf(
Keybinding(key = Key.S, control = true, alt = true),
),
KeybindingOption.OPEN_EDITOR to listOf(
Keybinding(key = Key.A, control = true, shift = true),
),
)

private fun linuxKeybindings(): Map<KeybindingOption, List<Keybinding>> = baseKeybindings()
Expand All @@ -179,6 +187,7 @@ private fun macKeybindings(): Map<KeybindingOption, List<Keybinding>> {
KeybindingOption.CHANGE_CURRENT_TAB_RIGHT,
KeybindingOption.CHANGE_CURRENT_TAB_LEFT,
KeybindingOption.SETTINGS,
KeybindingOption.OPEN_EDITOR,
)

for (key in keysToReplaceControlWithCommand) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ private const val PREF_GIT_PUSH_WITH_LEASE = "gitPushWithLease"

private const val PREF_VERIFY_SSL = "verifySsl"

private const val PREF_EDITOR = "editor"

private const val DEFAULT_SWAP_UNCOMMITTED_CHANGES = false
private const val DEFAULT_SHOW_CHANGES_AS_TREE = false
private const val DEFAULT_CACHE_CREDENTIALS_IN_MEMORY = true
Expand Down Expand Up @@ -91,6 +93,9 @@ class AppSettingsRepository @Inject constructor() {
private val _verifySslFlow = MutableStateFlow(cacheCredentialsInMemory)
val verifySslFlow = _verifySslFlow.asStateFlow()

private val _editorFlow = MutableStateFlow(editor)
val editorFlow = _editorFlow.asStateFlow()

private val _defaultCloneDirFlow = MutableStateFlow(defaultCloneDir)
val defaultCloneDirFlow = _defaultCloneDirFlow.asStateFlow()

Expand Down Expand Up @@ -241,6 +246,15 @@ class AppSettingsRepository @Inject constructor() {
_verifySslFlow.value = value
}

var editor: String
get() {
return preferences.get(PREF_EDITOR, "")
}
set(value) {
preferences.put(PREF_EDITOR, value)
_editorFlow.value = value
}

var scaleUi: Float
get() {
return preferences.getFloat(PREF_UI_SCALE, DEFAULT_UI_SCALE)
Expand Down
9 changes: 9 additions & 0 deletions src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,15 @@ fun Menu(
keybinding = null,
)

MenuButton(
modifier = Modifier.padding(end = 4.dp),
title = stringResource(Res.string.menu_editor),
icon = painterResource(Res.drawable.edit),
onClick = { menuViewModel.openEditor() },
tooltip = stringResource(Res.string.menu_editor_tooltip),
keybinding = KeybindingOption.OPEN_EDITOR.keyBinding,
)

MenuButton(
modifier = Modifier.padding(end = 4.dp),
title = stringResource(Res.string.menu_actions),
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ fun RepositoryOpenPage(
showQuickActionsDialog = false
when (it) {
QuickActionType.OPEN_DIR_IN_FILE_MANAGER -> repositoryOpenViewModel.openFolderInFileExplorer()
QuickActionType.OPEN_DIR_IN_EDITOR -> repositoryOpenViewModel.openFolderInEditor()
QuickActionType.CLONE -> onShowCloneDialog()
QuickActionType.REFRESH -> repositoryOpenViewModel.refreshAll()
QuickActionType.SIGN_OFF -> showSignOffDialog = true
Expand Down Expand Up @@ -165,6 +166,11 @@ fun RepositoryOpenPage(
true
}

it.matchesBinding(KeybindingOption.OPEN_EDITOR) -> {
repositoryOpenViewModel.openFolderInEditor()
true
}

else -> false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fun QuickActionsDialog(
val items = remember {
listOf(
QuickAction(Res.drawable.code, "Open repository in file manager", QuickActionType.OPEN_DIR_IN_FILE_MANAGER),
QuickAction(Res.drawable.code, "Open repository in editor", QuickActionType.OPEN_DIR_IN_EDITOR),
QuickAction(Res.drawable.download, "Clone new repository", QuickActionType.CLONE),
QuickAction(Res.drawable.refresh, "Refresh repository data", QuickActionType.REFRESH),
QuickAction(Res.drawable.sign, "Signoff config", QuickActionType.SIGN_OFF),
Expand Down Expand Up @@ -128,6 +129,7 @@ data class QuickAction(val icon: DrawableResource, val title: String, val type:

enum class QuickActionType {
OPEN_DIR_IN_FILE_MANAGER,
OPEN_DIR_IN_EDITOR,
CLONE,
REFRESH,
SIGN_OFF
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ val settings = listOf(

SettingsEntry.Section("Tools"),
SettingsEntry.Entry(Res.drawable.terminal, "Terminal") { Terminal(it) },
SettingsEntry.Entry(Res.drawable.edit, "Editor") { Editor(it) },
SettingsEntry.Entry(Res.drawable.info, "Logs") { Logs(it) },
)

Expand Down Expand Up @@ -357,6 +358,20 @@ private fun Security(settingsViewModel: SettingsViewModel) {
)
}

@Composable
fun Editor(settingsViewModel: SettingsViewModel) {
val editor by settingsViewModel.editorFlow.collectAsState()

SettingTextInput(
title = "External editor path",
subtitle = "Configure an external editor to open the repository with",
value = editor,
onValueChanged = { value ->
settingsViewModel.editor = value
},
)
}

@Composable
fun Terminal(settingsViewModel: SettingsViewModel) {
var commitsLimit by remember { mutableStateOf(settingsViewModel.terminalPath) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.jetpackduba.gitnuro.viewmodels

import com.jetpackduba.gitnuro.TaskType
import com.jetpackduba.gitnuro.editor.OpenRepositoryInEditorUseCase
import com.jetpackduba.gitnuro.git.RefreshType
import com.jetpackduba.gitnuro.git.TabState
import com.jetpackduba.gitnuro.git.remote_operations.FetchAllRemotesUseCase
Expand All @@ -23,6 +24,7 @@ interface IGlobalMenuActionsViewModel {
fun stash(): Job
fun popStash(): Job
fun openTerminal(): Job
fun openEditor(): Job
}

class GlobalMenuActionsViewModel @Inject constructor(
Expand All @@ -33,6 +35,7 @@ class GlobalMenuActionsViewModel @Inject constructor(
private val popLastStashUseCase: PopLastStashUseCase,
private val stashChangesUseCase: StashChangesUseCase,
private val openRepositoryInTerminalUseCase: OpenRepositoryInTerminalUseCase,
private val openRepositoryInEditorUseCase: OpenRepositoryInEditorUseCase,
) : IGlobalMenuActionsViewModel {
override fun pull(pullType: PullType) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA,
Expand Down Expand Up @@ -100,4 +103,10 @@ class GlobalMenuActionsViewModel @Inject constructor(
) { git ->
openRepositoryInTerminalUseCase(git.repository.workTree.absolutePath)
}

override fun openEditor() = tabState.runOperation(
refreshType = RefreshType.NONE
) { git ->
openRepositoryInEditorUseCase(git.repository.workTree.absolutePath)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.jetpackduba.gitnuro.viewmodels

import com.jetpackduba.gitnuro.SharedRepositoryStateManager
import com.jetpackduba.gitnuro.TaskType
import com.jetpackduba.gitnuro.editor.OpenRepositoryInEditorUseCase
import com.jetpackduba.gitnuro.exceptions.codeToMessage
import com.jetpackduba.gitnuro.git.*
import com.jetpackduba.gitnuro.git.branches.CreateBranchUseCase
Expand All @@ -12,10 +13,12 @@ import com.jetpackduba.gitnuro.logging.printDebug
import com.jetpackduba.gitnuro.logging.printLog
import com.jetpackduba.gitnuro.managers.AppStateManager
import com.jetpackduba.gitnuro.managers.ErrorsManager
import com.jetpackduba.gitnuro.managers.IShellManager
import com.jetpackduba.gitnuro.managers.newErrorNow
import com.jetpackduba.gitnuro.models.AuthorInfoSimple
import com.jetpackduba.gitnuro.models.errorNotification
import com.jetpackduba.gitnuro.models.positiveNotification
import com.jetpackduba.gitnuro.repositories.AppSettingsRepository
import com.jetpackduba.gitnuro.system.OpenFilePickerUseCase
import com.jetpackduba.gitnuro.system.OpenUrlInBrowserUseCase
import com.jetpackduba.gitnuro.system.PickerType
Expand Down Expand Up @@ -62,6 +65,7 @@ class RepositoryOpenViewModel @Inject constructor(
private val stashChangesUseCase: StashChangesUseCase,
private val stageUntrackedFileUseCase: StageUntrackedFileUseCase,
private val openFilePickerUseCase: OpenFilePickerUseCase,
private val openInEditorUseCase: OpenRepositoryInEditorUseCase,
private val openUrlInBrowserUseCase: OpenUrlInBrowserUseCase,
private val tabsManager: TabsManager,
private val tabScope: CoroutineScope,
Expand Down Expand Up @@ -352,6 +356,13 @@ class RepositoryOpenViewModel @Inject constructor(
Desktop.getDesktop().open(git.repository.workTree)
}

fun openFolderInEditor() = tabState.runOperation(
showError = true,
refreshType = RefreshType.NONE,
) { git ->
openInEditorUseCase(git.repository.workTree.path)
}

fun openUrlInBrowser(url: String) {
openUrlInBrowserUseCase(url)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class SettingsViewModel @Inject constructor(
val swapUncommittedChangesFlow = appSettingsRepository.swapUncommittedChangesFlow
val cacheCredentialsInMemoryFlow = appSettingsRepository.cacheCredentialsInMemoryFlow
val verifySslFlow = appSettingsRepository.verifySslFlow
val editorFlow = appSettingsRepository.editorFlow
val terminalPathFlow = appSettingsRepository.terminalPathFlow
val avatarProviderFlow = appSettingsRepository.avatarProviderTypeFlow
val dateFormatFlow = appSettingsRepository.dateTimeFormatFlow
Expand Down Expand Up @@ -90,6 +91,12 @@ class SettingsViewModel @Inject constructor(
appSettingsRepository.verifySsl = value
}

var editor: String
get() = appSettingsRepository.editor
set(value) {
appSettingsRepository.editor = value
}

var pullRebase: Boolean
get() = appSettingsRepository.pullRebase
set(value) {
Expand Down