Skip to content

Commit

Permalink
Adds alias list command and a cli selector menu
Browse files Browse the repository at this point in the history
Signed-off-by: Saahil Bhavsar <saahil_bhavsar@outlook.com>
  • Loading branch information
SaahilNotSahil committed Jul 22, 2024
1 parent 45d5bf1 commit e6c57bc
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 0 deletions.
35 changes: 35 additions & 0 deletions cli/cmd/alias/alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package alias

import (
"os"

"github.com/spf13/cobra"
)

type Alias struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
Value string `yaml:"value"`
}

type Aliases struct {
Aliases []Alias `yaml:"aliases"`
}

var AliasFilePath string

// AliasCmd represents the base alias command
var AliasCmd = &cobra.Command{
Use: "alias",
Short: "Use server aliases",
Long: "Use server aliases to connect to servers",
}

func init() {
homeDir, err := os.UserHomeDir()
if err != nil {
homeDir = "."
}

AliasFilePath = homeDir + "/.spok_aliases"
}
50 changes: 50 additions & 0 deletions cli/cmd/alias/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package alias

import (
"fmt"
"log"
"os"

"github.com/devlup-labs/spok/internal/pkg/selector"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)

// listCmd represents the alias list command
var listCmd = &cobra.Command{
Use: "list",
Short: "List all aliases",
Long: `List all aliases`,
Run: func(cmd *cobra.Command, args []string) {
data, err := os.ReadFile(AliasFilePath)
if err != nil {
return
}

aliases := new(Aliases)

err = yaml.Unmarshal(data, aliases)
if err != nil {
log.Println("Error reading the aliases file")

return
}

menu := selector.NewMenu("Choose your alias:")

for _, alias := range aliases.Aliases {
menu.AddItem(alias.Name, alias.Value)
}

choice := menu.Display()

numLinesToClear := len(menu.MenuItems) + 1
selector.ClearMenu(numLinesToClear)

fmt.Println(choice)
},
}

func init() {
AliasCmd.AddCommand(listCmd)
}
3 changes: 3 additions & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"github.com/devlup-labs/spok/cli/cmd/alias"
"github.com/spf13/cobra"
)

Expand All @@ -12,5 +13,7 @@ var rootCmd = &cobra.Command{
}

func Execute() {
rootCmd.AddCommand(alias.AliasCmd)

cobra.CheckErr(rootCmd.Execute())
}
132 changes: 132 additions & 0 deletions internal/pkg/selector/selector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package selector

import (
"fmt"
"log"

"github.com/buger/goterm"
"github.com/pkg/term"
)

type Menu struct {
Prompt string
CursorPos int
MenuItems []*MenuItem
}

type MenuItem struct {
Text string
ID string
}

var up byte = 65
var down byte = 66
var escape byte = 27
var enter byte = 13

var keys = map[byte]bool{
up: true,
down: true,
}

func (m *Menu) AddItem(option string, id string) *Menu {
menuItem := &MenuItem{
Text: option,
ID: id,
}

m.MenuItems = append(m.MenuItems, menuItem)

return m
}

func (m *Menu) renderMenuItems(redraw bool) {
if redraw {
fmt.Printf("\033[%dA", len(m.MenuItems)-1)
}

for index, menuItem := range m.MenuItems {
var newline = "\n"

if index == len(m.MenuItems)-1 {
newline = ""
}

menuItemText := menuItem.Text
cursor := " "
if index == m.CursorPos {
cursor = goterm.Color("> ", goterm.YELLOW)
menuItemText = goterm.Color(menuItemText, goterm.YELLOW)
}

fmt.Printf("\r%s %s%s", cursor, menuItemText, newline)
}
}

func (m *Menu) Display() string {
defer func() {
fmt.Printf("\033[?25h")
}()

fmt.Printf("%s\n", goterm.Color(goterm.Bold(m.Prompt)+":", goterm.CYAN))

m.renderMenuItems(false)

fmt.Printf("\033[?25l")

for {
keyCode := getInput()
if keyCode == escape {
return ""
} else if keyCode == enter {
menuItem := m.MenuItems[m.CursorPos]
fmt.Println("\r")
return menuItem.ID
} else if keyCode == up {
m.CursorPos = (m.CursorPos + len(m.MenuItems) - 1) % len(m.MenuItems)
m.renderMenuItems(true)
} else if keyCode == down {
m.CursorPos = (m.CursorPos + 1) % len(m.MenuItems)
m.renderMenuItems(true)
}
}
}

func getInput() byte {
t, _ := term.Open("/dev/tty")

err := term.RawMode(t)
if err != nil {
log.Fatal(err)
}

var read int
readBytes := make([]byte, 3)
read, err = t.Read(readBytes)

t.Restore()
t.Close()

if read == 3 {
if _, ok := keys[readBytes[2]]; ok {
return readBytes[2]
}
} else {
return readBytes[0]
}

return 0
}

func NewMenu(prompt string) *Menu {
return &Menu{
Prompt: prompt,
MenuItems: make([]*MenuItem, 0),
}
}

func ClearMenu(lines int) {
for i := 0; i < lines; i++ {
fmt.Print("\033[F\033[K")
}
}

0 comments on commit e6c57bc

Please sign in to comment.