Skip to content
Merged
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
12 changes: 11 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,28 @@ go 1.23

require (
github.com/briandowns/spinner v1.23.2
github.com/charmbracelet/lipgloss v1.1.0
github.com/fatih/color v1.18.0
github.com/muesli/termenv v0.16.0
github.com/schollz/progressbar/v3 v3.18.0
github.com/spf13/cobra v1.10.1
golang.org/x/sys v0.29.0
golang.org/x/sys v0.30.0
)

require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/x/ansi v0.8.0 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/term v0.28.0 // indirect
)
25 changes: 23 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/briandowns/spinner v1.23.2 h1:Zc6ecUnI+YzLmJniCfDNaMbW0Wid1d5+qcTq4L2FW8w=
github.com/briandowns/spinner v1.23.2/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
Expand All @@ -9,6 +21,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
Expand All @@ -18,8 +32,11 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
Expand All @@ -32,10 +49,14 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"build": "npm run build:cli && npm run build:shim",
"build:cli": "go build -v -ldflags=\"-s -w\" -o dist/dtvem.exe ./src",
"build:shim": "go build -v -ldflags=\"-s -w\" -o dist/dtvem-shim.exe ./src/cmd/shim",
"install": "npm run build && cp dist/dtvem.exe ~/.dtvem/bin/dtvem.exe && cp dist/dtvem-shim.exe ~/.dtvem/bin/dtvem-shim.exe && ~/.dtvem/bin/dtvem.exe reshim",
"deploy:local": "npm run build && copy dist\\dtvem.exe %USERPROFILE%\\.dtvem\\bin\\dtvem.exe && copy dist\\dtvem-shim.exe %USERPROFILE%\\.dtvem\\bin\\dtvem-shim.exe && echo Deploy complete. Run 'dtvem reshim' manually to update shims.",
"clean": "rm -rf dist coverage.out coverage.html",
"check": "npm run format && npm run lint && npm run test"
},
Expand Down
20 changes: 15 additions & 5 deletions src/cmd/current.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/dtvem/dtvem/src/internal/runtime"
"github.com/dtvem/dtvem/src/internal/tui"
"github.com/dtvem/dtvem/src/internal/ui"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -66,17 +67,21 @@ func showAllVersions() {
}

// Display all configured versions
ui.Header("Currently active versions:")
table := tui.NewTable("Runtime", "Version", "Status")
table.SetTitle("Active Versions")
var missing []runtimeStatus

for _, rs := range configured {
if rs.installed {
fmt.Printf(" %s: %s\n", ui.Highlight(rs.provider.DisplayName()), ui.HighlightVersion(rs.version))
table.AddActiveRow(rs.provider.DisplayName(), rs.version, tui.CheckMark+" installed")
} else {
ui.Warning("%s: %s (not installed)", rs.provider.DisplayName(), rs.version)
table.AddRow(rs.provider.DisplayName(), rs.version, tui.CrossMark+" not installed")
missing = append(missing, rs)
}
}

fmt.Println(table.Render())

// Prompt to install missing versions
if len(missing) > 0 {
fmt.Println()
Expand Down Expand Up @@ -109,13 +114,18 @@ func showSingleVersion(runtimeName string) {
}

installed, _ := provider.IsInstalled(version)

table := tui.NewTable("Runtime", "Version", "Status")
if installed {
fmt.Printf("%s: %s\n", ui.Highlight(provider.DisplayName()), ui.HighlightVersion(version))
table.AddActiveRow(provider.DisplayName(), version, tui.CheckMark+" installed")
fmt.Println(table.Render())
return
}

// Not installed - show with warning and prompt
ui.Warning("%s: %s (not installed)", provider.DisplayName(), version)
table.AddRow(provider.DisplayName(), version, tui.CrossMark+" not installed")
fmt.Println(table.Render())

fmt.Println()
if ui.PromptInstall(provider.DisplayName(), version) {
if err := provider.Install(version); err != nil {
Expand Down
79 changes: 56 additions & 23 deletions src/cmd/list.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package cmd

import (
"fmt"

"github.com/dtvem/dtvem/src/internal/config"
"github.com/dtvem/dtvem/src/internal/runtime"
"github.com/dtvem/dtvem/src/internal/tui"
"github.com/dtvem/dtvem/src/internal/ui"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -41,8 +44,6 @@ func listAllRuntimes() {
return
}

ui.Header("Installed versions:")

hasAny := false
for _, provider := range providers {
versions, err := provider.ListInstalled()
Expand All @@ -60,10 +61,23 @@ func listAllRuntimes() {
globalVersion, _ := provider.GlobalVersion()
localVersion, _ := config.LocalVersion(runtimeName)

ui.Printf(" %s:\n", ui.Highlight(provider.DisplayName()))
// Create table for this runtime with title
table := tui.NewTable("Version", "Status")
table.SetTitle(provider.DisplayName())

for _, v := range versions {
printVersionLine(v.String(), globalVersion, localVersion)
version := v.String()
status := getVersionStatus(version, globalVersion, localVersion)
isActive := isVersionActive(version, globalVersion, localVersion)

if isActive {
table.AddActiveRow(version, status)
} else {
table.AddRow(version, status)
}
}

fmt.Println(table.Render())
}

if !hasAny {
Expand All @@ -80,8 +94,6 @@ func listSingleRuntime(runtimeName string) {
return
}

ui.Header("Installed %s versions:", provider.DisplayName())

versions, err := provider.ListInstalled()
if err != nil {
ui.Error("%v", err)
Expand All @@ -96,36 +108,57 @@ func listSingleRuntime(runtimeName string) {
globalVersion, _ := provider.GlobalVersion()
localVersion, _ := config.LocalVersion(runtimeName)

// Create table with title
table := tui.NewTable("Version", "Status")
table.SetTitle(provider.DisplayName())

for _, v := range versions {
printVersionLine(v.String(), globalVersion, localVersion)
version := v.String()
status := getVersionStatus(version, globalVersion, localVersion)
isActive := isVersionActive(version, globalVersion, localVersion)

if isActive {
table.AddActiveRow(version, status)
} else {
table.AddRow(version, status)
}
}

fmt.Println(table.Render())
}

// printVersionLine prints a single version with appropriate indicators and colors
// Active version (local > global) is shown in green
// Indicators: 🌐 for global, 📍 for local
func printVersionLine(version, globalVersion, localVersion string) {
// getVersionStatus returns a status string for a version (global, local, or empty)
func getVersionStatus(version, globalVersion, localVersion string) string {
isGlobal := version == globalVersion
isLocal := version == localVersion

// Determine if this is the active version (local takes priority over global)
isActive := isLocal || (isGlobal && localVersion == "")

// Build the indicator string
var indicators string
var parts []string
if isLocal {
indicators += " " + localIndicator
parts = append(parts, localIndicator+" local")
}
if isGlobal {
indicators += " " + globalIndicator
parts = append(parts, globalIndicator+" global")
}

// Format and print
if isActive {
ui.Printf(" %s%s\n", ui.ActiveVersion(version), indicators)
} else {
ui.Printf(" %s%s\n", version, indicators)
if len(parts) == 0 {
return ""
}

status := ""
for i, p := range parts {
if i > 0 {
status += ", "
}
status += p
}
return status
}

// isVersionActive returns true if this version is the currently active one
func isVersionActive(version, globalVersion, localVersion string) bool {
isGlobal := version == globalVersion
isLocal := version == localVersion
return isLocal || (isGlobal && localVersion == "")
}

func init() {
Expand Down
Loading