From 5b5d3118947378ac095199723252e5f7f9c13bda Mon Sep 17 00:00:00 2001 From: hunnywar Date: Fri, 10 Jan 2025 15:26:46 +0530 Subject: [PATCH 1/2] feat: add support for Vim IDE Signed-off-by: hunnywar --- cmd/daytona/config/const.go | 1 + docs/daytona_code.md | 2 +- docs/daytona_create.md | 2 +- hack/docs/daytona_code.yaml | 2 +- hack/docs/daytona_create.yaml | 2 +- pkg/cmd/ide.go | 5 +++ pkg/cmd/workspace/code.go | 2 ++ pkg/ide/vim.go | 59 +++++++++++++++++++++++++++++++++++ 8 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 pkg/ide/vim.go diff --git a/cmd/daytona/config/const.go b/cmd/daytona/config/const.go index 243a32683b..269cec57aa 100644 --- a/cmd/daytona/config/const.go +++ b/cmd/daytona/config/const.go @@ -31,6 +31,7 @@ func GetIdeList() []Ide { {"codium", "VSCodium"}, {"codium-insiders", "VSCodium Insiders"}, {"ssh", "Terminal SSH"}, + {"vim", "Vim"}, {"jupyter", "Jupyter"}, {"fleet", "Fleet"}, {"positron", "Positron"}, diff --git a/docs/daytona_code.md b/docs/daytona_code.md index a37f6d179b..c856b32e12 100644 --- a/docs/daytona_code.md +++ b/docs/daytona_code.md @@ -9,7 +9,7 @@ daytona code [WORKSPACE] [PROJECT] [flags] ### Options ``` - -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, vim, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) -y, --yes Automatically confirm any prompts ``` diff --git a/docs/daytona_create.md b/docs/daytona_create.md index 03f852d4df..e3e3da5b9f 100644 --- a/docs/daytona_create.md +++ b/docs/daytona_create.md @@ -17,7 +17,7 @@ daytona create [REPOSITORY_URL | PROJECT_CONFIG_NAME]... [flags] --devcontainer-path string Automatically assign the devcontainer builder with the path passed as the flag value --env stringArray Specify environment variables (e.g. --env 'KEY1=VALUE1' --env 'KEY2=VALUE2' ...') --git-provider-config string Specify the Git provider configuration ID or alias - -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, vim, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) --manual Manually enter the Git repository --multi-project Workspace with multiple projects/repos --name string Specify the workspace name diff --git a/hack/docs/daytona_code.yaml b/hack/docs/daytona_code.yaml index 049123a7d7..2f1f69daca 100644 --- a/hack/docs/daytona_code.yaml +++ b/hack/docs/daytona_code.yaml @@ -5,7 +5,7 @@ options: - name: ide shorthand: i usage: | - Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, vim, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) - name: "yes" shorthand: "y" default_value: "false" diff --git a/hack/docs/daytona_create.yaml b/hack/docs/daytona_create.yaml index d8afd7b6ab..76b059dfe6 100644 --- a/hack/docs/daytona_create.yaml +++ b/hack/docs/daytona_create.yaml @@ -28,7 +28,7 @@ options: - name: ide shorthand: i usage: | - Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, vim, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) - name: manual default_value: "false" usage: Manually enter the Git repository diff --git a/pkg/cmd/ide.go b/pkg/cmd/ide.go index 788415f1fb..a17a3ee7b1 100644 --- a/pkg/cmd/ide.go +++ b/pkg/cmd/ide.go @@ -66,6 +66,11 @@ var ideCmd = &cobra.Command{ if err != nil { log.Error(err) } + case "vim": + _, err := ide_util.GetVimBinaryPath() + if err != nil { + log.Error(err) + } case "fleet": if err := ide_util.CheckFleetInstallation(); err != nil { log.Error(err) diff --git a/pkg/cmd/workspace/code.go b/pkg/cmd/workspace/code.go index 74e0fb4df3..169570f31b 100644 --- a/pkg/cmd/workspace/code.go +++ b/pkg/cmd/workspace/code.go @@ -187,6 +187,8 @@ func openIDE(ideId string, activeProfile config.Profile, workspaceId string, pro return ide.OpenTerminalSsh(activeProfile, workspaceId, projectName, gpgKey, nil) case "browser": return ide.OpenBrowserIDE(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) + case "vim": + return ide.OpenVim(activeProfile, workspaceId, projectName, gpgKey) case "codium": return ide.OpenVScodium(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) case "codium-insiders": diff --git a/pkg/ide/vim.go b/pkg/ide/vim.go new file mode 100644 index 0000000000..210b999cab --- /dev/null +++ b/pkg/ide/vim.go @@ -0,0 +1,59 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package ide + +import ( + "errors" + "fmt" + "os" + "os/exec" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/views" +) + +func OpenVim(activeProfile config.Profile, workspaceId, projectName, gpgKey string) error { + path, err := GetVimBinaryPath() + if err != nil { + return err + } + + printVimDisclaimer() + projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) + if err != nil { + return err + } + // This suppresses the "Permanently added ... to the list of known hosts" message and reduce file listing errors + vimConfig := fmt.Sprintf(`:let g:netrw_list_cmd = "ssh -o LogLevel=QUIET %s ls -Fa"`, projectHostname) + + // Both scp and sftp are supported by Vim's built-in netrw plugin + vimCmd := exec.Command(path, "-c", vimConfig, fmt.Sprintf("scp://%s/%s/", projectHostname, projectDir)) + vimCmd.Stdin = os.Stdin + vimCmd.Stdout = os.Stdout + vimCmd.Stderr = os.Stderr + + return vimCmd.Run() +} + +func GetVimBinaryPath() (string, error) { + path, err := exec.LookPath("vim") + if err == nil { + return path, err + } + + redBold := "\033[1;31m" // ANSI escape code for red and bold + reset := "\033[0m" // ANSI escape code to reset text formatting + + errorMessage := "Please install Vim and ensure it's in your PATH.\n" + + return "", errors.New(redBold + errorMessage + reset) +} + +func printVimDisclaimer() { + views.RenderTip(`Note: Vim only allows you to edit remote files using Netrw. +For a better experience, consider using a dedicated IDE. +If you need to run commands, please use the 'daytona ssh' command instead.`) +} From a00c1ab577e8e3afa88109894e6692d10a5a786b Mon Sep 17 00:00:00 2001 From: hunnywar Date: Wed, 15 Jan 2025 14:47:19 +0530 Subject: [PATCH 2/2] refactor code , make it reusable Signed-off-by: hunnywar --- pkg/cmd/ide.go | 2 +- pkg/cmd/workspace/code.go | 2 +- pkg/ide/vim.go | 38 +++++++++++++++++++++----------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/pkg/cmd/ide.go b/pkg/cmd/ide.go index a17a3ee7b1..ae6dc0a655 100644 --- a/pkg/cmd/ide.go +++ b/pkg/cmd/ide.go @@ -67,7 +67,7 @@ var ideCmd = &cobra.Command{ log.Error(err) } case "vim": - _, err := ide_util.GetVimBinaryPath() + _, err := ide_util.GetEditorBinaryPath("Vim") if err != nil { log.Error(err) } diff --git a/pkg/cmd/workspace/code.go b/pkg/cmd/workspace/code.go index 169570f31b..1e03af9a40 100644 --- a/pkg/cmd/workspace/code.go +++ b/pkg/cmd/workspace/code.go @@ -188,7 +188,7 @@ func openIDE(ideId string, activeProfile config.Profile, workspaceId string, pro case "browser": return ide.OpenBrowserIDE(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) case "vim": - return ide.OpenVim(activeProfile, workspaceId, projectName, gpgKey) + return ide.OpenEditor("Vim", activeProfile, workspaceId, projectName, gpgKey) case "codium": return ide.OpenVScodium(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) case "codium-insiders": diff --git a/pkg/ide/vim.go b/pkg/ide/vim.go index 210b999cab..e99a3011cc 100644 --- a/pkg/ide/vim.go +++ b/pkg/ide/vim.go @@ -8,38 +8,41 @@ import ( "fmt" "os" "os/exec" + "strings" "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/views" ) -func OpenVim(activeProfile config.Profile, workspaceId, projectName, gpgKey string) error { - path, err := GetVimBinaryPath() +// OpenEditor opens the specified editor (vim/nvim) for a given project +func OpenEditor(editorBinary string, activeProfile config.Profile, workspaceId, projectName, gpgKey string) error { + path, err := GetEditorBinaryPath(editorBinary) if err != nil { return err } - printVimDisclaimer() + printEditorDisclaimer(editorBinary) projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) if err != nil { return err } - // This suppresses the "Permanently added ... to the list of known hosts" message and reduce file listing errors - vimConfig := fmt.Sprintf(`:let g:netrw_list_cmd = "ssh -o LogLevel=QUIET %s ls -Fa"`, projectHostname) + // Suppresses "Permanently added ... to the list of known hosts" message and reduces file listing errors + editorConfig := fmt.Sprintf(`:let g:netrw_list_cmd = "ssh -o LogLevel=QUIET %s ls -Fa"`, projectHostname) - // Both scp and sftp are supported by Vim's built-in netrw plugin - vimCmd := exec.Command(path, "-c", vimConfig, fmt.Sprintf("scp://%s/%s/", projectHostname, projectDir)) - vimCmd.Stdin = os.Stdin - vimCmd.Stdout = os.Stdout - vimCmd.Stderr = os.Stderr + // Both scp and sftp are supported by Vim/Nvim's built-in netrw plugin + editorCmd := exec.Command(path, "-c", editorConfig, fmt.Sprintf("scp://%s/%s/", projectHostname, projectDir)) + editorCmd.Stdin = os.Stdin + editorCmd.Stdout = os.Stdout + editorCmd.Stderr = os.Stderr - return vimCmd.Run() + return editorCmd.Run() } -func GetVimBinaryPath() (string, error) { - path, err := exec.LookPath("vim") +// GetEditorBinaryPath returns the path to the specified editor binary +func GetEditorBinaryPath(editorBinary string) (string, error) { + path, err := exec.LookPath(strings.ToLower(editorBinary)) if err == nil { return path, err } @@ -47,13 +50,14 @@ func GetVimBinaryPath() (string, error) { redBold := "\033[1;31m" // ANSI escape code for red and bold reset := "\033[0m" // ANSI escape code to reset text formatting - errorMessage := "Please install Vim and ensure it's in your PATH.\n" + errorMessage := fmt.Sprintf("Please install %s and ensure it's in your PATH.\n", editorBinary) return "", errors.New(redBold + errorMessage + reset) } -func printVimDisclaimer() { - views.RenderTip(`Note: Vim only allows you to edit remote files using Netrw. +// printEditorDisclaimer displays a disclaimer message for the specified editor +func printEditorDisclaimer(editorName string) { + views.RenderTip(fmt.Sprintf(`Note: %s only allows you to edit remote files using Netrw. For a better experience, consider using a dedicated IDE. -If you need to run commands, please use the 'daytona ssh' command instead.`) +If you need to run commands, please use the 'daytona ssh' command instead.`, editorName)) }