First working version
This commit is contained in:
186
internal/prompt/prompt.go
Normal file
186
internal/prompt/prompt.go
Normal file
@ -0,0 +1,186 @@
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
var (
|
||||
cyan = color.New(color.FgCyan).SprintFunc()
|
||||
green = color.New(color.FgGreen).SprintFunc()
|
||||
yellow = color.New(color.FgYellow).SprintFunc()
|
||||
red = color.New(color.FgRed).SprintFunc()
|
||||
)
|
||||
|
||||
// Reader interface for testing
|
||||
type Reader interface {
|
||||
ReadString(delim byte) (string, error)
|
||||
}
|
||||
|
||||
// PromptString prompts for a string value
|
||||
func PromptString(label string, defaultValue string, required bool) (string, error) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
return promptStringWithReader(reader, label, defaultValue, required)
|
||||
}
|
||||
|
||||
func promptStringWithReader(reader Reader, label string, defaultValue string, required bool) (string, error) {
|
||||
for {
|
||||
prompt := fmt.Sprintf("%s", cyan(label))
|
||||
if defaultValue != "" {
|
||||
prompt += fmt.Sprintf(" [%s]", green(defaultValue))
|
||||
}
|
||||
prompt += ": "
|
||||
|
||||
fmt.Print(prompt)
|
||||
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
input = strings.TrimSpace(input)
|
||||
|
||||
// If input is empty, use default value
|
||||
if input == "" {
|
||||
if defaultValue != "" {
|
||||
// Echo the selected default value
|
||||
fullPrompt := fmt.Sprintf("%s [%s]: %s", cyan(label), green(defaultValue), defaultValue)
|
||||
fmt.Printf("\033[1A\r%s\n", fullPrompt)
|
||||
return defaultValue, nil
|
||||
}
|
||||
if required {
|
||||
fmt.Println(red("✗ This field is required"))
|
||||
continue
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return input, nil
|
||||
}
|
||||
}
|
||||
|
||||
// PromptInt prompts for an integer value
|
||||
func PromptInt(label string, defaultValue int, required bool) (int, error) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
return promptIntWithReader(reader, label, defaultValue, required)
|
||||
}
|
||||
|
||||
func promptIntWithReader(reader Reader, label string, defaultValue int, required bool) (int, error) {
|
||||
for {
|
||||
defaultStr := ""
|
||||
if defaultValue != 0 {
|
||||
defaultStr = strconv.Itoa(defaultValue)
|
||||
}
|
||||
|
||||
prompt := fmt.Sprintf("%s", cyan(label))
|
||||
if defaultStr != "" {
|
||||
prompt += fmt.Sprintf(" [%s]", green(defaultStr))
|
||||
}
|
||||
prompt += ": "
|
||||
|
||||
fmt.Print(prompt)
|
||||
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
input = strings.TrimSpace(input)
|
||||
|
||||
// If input is empty, use default value
|
||||
if input == "" {
|
||||
if defaultValue != 0 {
|
||||
// Echo the selected default value
|
||||
fullPrompt := fmt.Sprintf("%s [%s]: %s", cyan(label), green(defaultStr), defaultStr)
|
||||
fmt.Printf("\033[1A\r%s\n", fullPrompt)
|
||||
return defaultValue, nil
|
||||
}
|
||||
if required {
|
||||
fmt.Println(red("✗ This field is required"))
|
||||
continue
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Parse integer
|
||||
value, err := strconv.Atoi(input)
|
||||
if err != nil {
|
||||
fmt.Println(red("✗ Please enter a valid number"))
|
||||
continue
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateDirectory checks if a directory exists or can be created
|
||||
func ValidateDirectory(path string) error {
|
||||
// Check if path exists
|
||||
info, err := os.Stat(path)
|
||||
if err == nil {
|
||||
// Path exists, check if it's a directory
|
||||
if !info.IsDir() {
|
||||
return fmt.Errorf("path exists but is not a directory")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Path doesn't exist, try to create it
|
||||
if os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return fmt.Errorf("cannot create directory: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// PromptDirectory prompts for a directory path and validates it
|
||||
func PromptDirectory(label string, defaultValue string, required bool) (string, error) {
|
||||
for {
|
||||
path, err := PromptString(label, defaultValue, required)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if path == "" && !required {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Validate directory
|
||||
if err := ValidateDirectory(path); err != nil {
|
||||
fmt.Printf("%s %s\n", red("✗"), err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
|
||||
// PrintHeader prints a colored header
|
||||
func PrintHeader(text string) {
|
||||
header := color.New(color.FgCyan, color.Bold)
|
||||
header.Println("\n" + text)
|
||||
header.Println(strings.Repeat("=", len(text)))
|
||||
}
|
||||
|
||||
// PrintSuccess prints a success message
|
||||
func PrintSuccess(text string) {
|
||||
fmt.Printf("%s %s\n", green("✓"), text)
|
||||
}
|
||||
|
||||
// PrintError prints an error message
|
||||
func PrintError(text string) {
|
||||
fmt.Printf("%s %s\n", red("✗"), text)
|
||||
}
|
||||
|
||||
// PrintInfo prints an info message
|
||||
func PrintInfo(text string) {
|
||||
fmt.Printf("%s %s\n", yellow("ℹ"), text)
|
||||
}
|
||||
Reference in New Issue
Block a user