Added button to open terminal in current directory

Fixes #36
This commit is contained in:
Abdelilah El Aissaoui 2023-03-21 01:37:05 +01:00
parent 856df1e64a
commit f069360e07
No known key found for this signature in database
GPG Key ID: 7587FC860F594869
15 changed files with 207 additions and 6 deletions

View File

@ -62,6 +62,9 @@ class App {
@Inject
lateinit var appGpgSigner: AppGpgSigner
@Inject
lateinit var appEnvInfo: AppEnvInfo
init {
appComponent.inject(this)
}
@ -73,6 +76,7 @@ class App {
val dirToOpen = getDirToOpen(args)
var defaultSelectedTabKey = 0
appEnvInfo.isFlatpak = args.contains("--flatpak") // TODO Test this
appStateManager.loadRepositoriesTabs()
try {

View File

@ -0,0 +1,9 @@
package com.jetpackduba.gitnuro
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AppEnvInfo @Inject constructor() {
var isFlatpak = false
}

View File

@ -1,6 +1,7 @@
package com.jetpackduba.gitnuro.di
import com.jetpackduba.gitnuro.App
import com.jetpackduba.gitnuro.AppEnvInfo
import com.jetpackduba.gitnuro.AppStateManager
import com.jetpackduba.gitnuro.credentials.CredentialsStateManager
import com.jetpackduba.gitnuro.di.modules.AppModule
@ -22,4 +23,6 @@ interface AppComponent {
fun credentialsStateManager(): CredentialsStateManager
fun appPreferences(): AppSettings
fun appEnvInfo(): AppEnvInfo
}

View File

@ -2,6 +2,7 @@ package com.jetpackduba.gitnuro.di
import com.jetpackduba.gitnuro.di.modules.NetworkModule
import com.jetpackduba.gitnuro.di.modules.TabModule
import com.jetpackduba.gitnuro.di.modules.TerminalModule
import com.jetpackduba.gitnuro.ui.components.TabInformation
import dagger.Component
@ -10,6 +11,7 @@ import dagger.Component
modules = [
NetworkModule::class,
TabModule::class,
TerminalModule::class,
],
dependencies = [
AppComponent::class

View File

@ -0,0 +1,32 @@
package com.jetpackduba.gitnuro.di.modules
import com.jetpackduba.gitnuro.AppEnvInfo
import com.jetpackduba.gitnuro.extensions.OS
import com.jetpackduba.gitnuro.extensions.getCurrentOs
import com.jetpackduba.gitnuro.terminal.*
import dagger.Module
import dagger.Provides
import javax.inject.Provider
@Module
class TerminalModule {
@Provides
fun provideTerminalProvider(
linuxTerminalProvider: Provider<LinuxTerminalProvider>,
windowsTerminalProvider: Provider<WindowsTerminalProvider>,
macTerminalProvider: Provider<MacTerminalProvider>,
flatpakTerminalProvider: Provider<FlatpakTerminalProvider>,
appEnvInfo: AppEnvInfo,
): ITerminalProvider {
if (appEnvInfo.isFlatpak)
return flatpakTerminalProvider.get()
return when (getCurrentOs()) {
OS.LINUX -> linuxTerminalProvider.get()
OS.WINDOWS -> windowsTerminalProvider.get()
OS.MAC -> macTerminalProvider.get()
OS.UNKNOWN -> throw NotImplementedError("Unknown operating system")
}
}
}

View File

@ -1,6 +1,7 @@
package com.jetpackduba.gitnuro.extensions
import com.jetpackduba.gitnuro.logging.printLog
import java.io.File
import java.io.IOException
import java.util.*
@ -25,6 +26,14 @@ fun runCommand(command: String): String? {
}
}
fun runCommandInPath(command: String, path: String) {
val processBuilder = ProcessBuilder(command).apply {
directory(File(path))
}
processBuilder.start()
}
fun runCommandWithoutResult(command: String, args: String, file: String): Boolean {
val parts: Array<String> = prepareCommand(command, args, file)

View File

@ -0,0 +1,27 @@
package com.jetpackduba.gitnuro.terminal
import com.jetpackduba.gitnuro.extensions.runCommand
import com.jetpackduba.gitnuro.extensions.runCommandInPath
import javax.inject.Inject
private const val FLATPAK_PREFIX = "/usr/bin/flatpak-spawn --host --env=TERM=xterm-256color"
// TODO Test in flatpak
class FlatpakTerminalProvider @Inject constructor(
private val linuxTerminalProvider: LinuxTerminalProvider,
) : ITerminalProvider {
override fun getTerminalEmulators(): List<TerminalEmulator> {
return linuxTerminalProvider.getTerminalEmulators()
}
override fun isTerminalInstalled(terminalEmulator: TerminalEmulator): Boolean {
val checkTerminalInstalled = runCommand("$FLATPAK_PREFIX which ${terminalEmulator.path} 2>/dev/null")
return !checkTerminalInstalled.isNullOrEmpty()
}
override fun startTerminal(terminalEmulator: TerminalEmulator, repositoryPath: String) {
runCommandInPath("$FLATPAK_PREFIX ${terminalEmulator.path}", repositoryPath)
}
}

View File

@ -0,0 +1,9 @@
package com.jetpackduba.gitnuro.terminal
interface ITerminalProvider {
fun getTerminalEmulators(): List<TerminalEmulator>
fun isTerminalInstalled(terminalEmulator: TerminalEmulator): Boolean
fun startTerminal(terminalEmulator: TerminalEmulator, repositoryPath: String)
}

View File

@ -0,0 +1,27 @@
package com.jetpackduba.gitnuro.terminal
import com.jetpackduba.gitnuro.extensions.runCommand
import com.jetpackduba.gitnuro.extensions.runCommandInPath
import javax.inject.Inject
class LinuxTerminalProvider @Inject constructor() : ITerminalProvider {
override fun getTerminalEmulators(): List<TerminalEmulator> {
return listOf(
TerminalEmulator("Gnome Terminal", "gnome-terminal"),
TerminalEmulator("KDE Terminal", "kde-terminal"),
TerminalEmulator("XFCE Terminal", "xfce4-terminal"),
TerminalEmulator("Mate Terminal", "mate-terminal"),
TerminalEmulator("LXQT Terminal", "qterminal"),
)
}
override fun isTerminalInstalled(terminalEmulator: TerminalEmulator): Boolean {
val checkTerminalInstalled = runCommand("which ${terminalEmulator.path} 2>/dev/null")
return !checkTerminalInstalled.isNullOrEmpty()
}
override fun startTerminal(terminalEmulator: TerminalEmulator, repositoryPath: String) {
runCommandInPath(terminalEmulator.path, repositoryPath)
}
}

View File

@ -0,0 +1,24 @@
package com.jetpackduba.gitnuro.terminal
import com.jetpackduba.gitnuro.extensions.runCommand
import com.jetpackduba.gitnuro.extensions.runCommandInPath
import javax.inject.Inject
// TODO Test this on MacOS
class MacTerminalProvider @Inject constructor() : ITerminalProvider {
override fun getTerminalEmulators(): List<TerminalEmulator> {
return listOf(
TerminalEmulator("MacOS Terminal", "Terminal")
)
}
override fun isTerminalInstalled(terminalEmulator: TerminalEmulator): Boolean {
val checkTerminalInstalled = runCommand("which ${terminalEmulator.path} 2>/dev/null")
return !checkTerminalInstalled.isNullOrEmpty()
}
override fun startTerminal(terminalEmulator: TerminalEmulator, repositoryPath: String) {
runCommandInPath("open -a ${terminalEmulator.path}", repositoryPath)
}
}

View File

@ -0,0 +1,22 @@
package com.jetpackduba.gitnuro.terminal
import com.jetpackduba.gitnuro.extensions.runCommandInPath
import javax.inject.Inject
// For flatpak: https://github.com/flathub/com.visualstudio.code#use-host-shell-in-the-integrated-terminal
class OpenRepositoryInTerminalUseCase @Inject constructor(
private val terminalProvider: ITerminalProvider
) {
operator fun invoke(path: String) {
val terminalEmulators = terminalProvider.getTerminalEmulators()
for (terminal in terminalEmulators) {
val isTerminalEmulatorInstalled = terminalProvider.isTerminalInstalled(terminal)
if (isTerminalEmulatorInstalled) {
runCommandInPath(terminal.path, path)
break
}
}
}
}

View File

@ -0,0 +1,3 @@
package com.jetpackduba.gitnuro.terminal
data class TerminalEmulator(val name: String, val path: String)

View File

@ -0,0 +1,22 @@
package com.jetpackduba.gitnuro.terminal
import com.jetpackduba.gitnuro.extensions.runCommandInPath
import javax.inject.Inject
// TODO Test this on windows
class WindowsTerminalProvider @Inject constructor() : ITerminalProvider {
override fun getTerminalEmulators(): List<TerminalEmulator> {
return listOf(
TerminalEmulator("Powershell", "powershell"),
)
}
override fun isTerminalInstalled(terminalEmulator: TerminalEmulator): Boolean {
// TODO how do we know if it's installed? We must check the output when trying to start an app that doesn't exist
return true
}
override fun startTerminal(terminalEmulator: TerminalEmulator, repositoryPath: String) {
runCommandInPath("start ${terminalEmulator.path}", repositoryPath)
}
}

View File

@ -127,12 +127,12 @@ fun Menu(
Spacer(modifier = Modifier.weight(1f))
// MenuButton(
// modifier = Modifier.padding(end = 4.dp),
// title = "Terminal",
// icon = painterResource("terminal.svg"),
// onClick = onQuickActions,
// )
MenuButton(
modifier = Modifier.padding(end = 4.dp),
title = "Terminal",
icon = painterResource(AppIcons.TERMINAL),
onClick = { menuViewModel.openTerminal() },
)
MenuButton(
modifier = Modifier.padding(end = 4.dp),

View File

@ -10,6 +10,7 @@ import com.jetpackduba.gitnuro.git.stash.PopLastStashUseCase
import com.jetpackduba.gitnuro.git.stash.StashChangesUseCase
import com.jetpackduba.gitnuro.git.workspace.StageUntrackedFileUseCase
import com.jetpackduba.gitnuro.preferences.AppSettings
import com.jetpackduba.gitnuro.terminal.OpenRepositoryInTerminalUseCase
import javax.inject.Inject
class MenuViewModel @Inject constructor(
@ -20,6 +21,7 @@ class MenuViewModel @Inject constructor(
private val popLastStashUseCase: PopLastStashUseCase,
private val stashChangesUseCase: StashChangesUseCase,
private val stageUntrackedFileUseCase: StageUntrackedFileUseCase,
private val openRepositoryInTerminalUseCase: OpenRepositoryInTerminalUseCase,
private val settings: AppSettings,
) {
val isPullWithRebaseDefault = settings.pullRebaseFlow
@ -58,4 +60,10 @@ class MenuViewModel @Inject constructor(
) { git ->
popLastStashUseCase(git)
}
fun openTerminal() = tabState.runOperation(
refreshType = RefreshType.NONE
) { git ->
openRepositoryInTerminalUseCase(git.repository.directory.parent)
}
}