From 33ac4c8eaa297a7e48e96ab8e7715651a965b4bf Mon Sep 17 00:00:00 2001 From: Robin Olsen Date: Fri, 6 Feb 2026 23:32:40 +0100 Subject: [PATCH] move repl file --- pkg/cli/repl.go | 300 ------------------------------------------------ 1 file changed, 300 deletions(-) delete mode 100644 pkg/cli/repl.go diff --git a/pkg/cli/repl.go b/pkg/cli/repl.go deleted file mode 100644 index 1858f38..0000000 --- a/pkg/cli/repl.go +++ /dev/null @@ -1,300 +0,0 @@ -package cli - -import ( - "context" - "fmt" - "os" - "os/exec" - "strings" - - "github.com/LazyBachelor/LazyPM/internal/service" - "github.com/LazyBachelor/LazyPM/pkg" - "github.com/LazyBachelor/LazyPM/pkg/cli/commands" - "github.com/c-bata/go-prompt" - "github.com/charmbracelet/lipgloss" - "github.com/muesli/reflow/truncate" - "golang.org/x/term" -) - -func RunREPL(ctx context.Context, config pkg.SurveyConfig) error { - oldState, err := term.GetState(int(os.Stdin.Fd())) - if err != nil { - return fmt.Errorf("failed to get terminal state: %w", err) - } - - svc, cleanup, err := service.NewServices(ctx, config) - if err != nil { - return fmt.Errorf("failed to initialize services: %w", err) - } - defer cleanup() - - commands.SetServices(svc) - - titleStyle := lipgloss.NewStyle().Align(lipgloss.Center).Bold(true).Border(lipgloss.RoundedBorder()).Padding(1).Foreground(lipgloss.Color("6")) - - title := `Welcome to Project Management CLI! Type 'pm help' for available commands. -You can also run shell commands directly. Type 'exit' or 'quit' to leave.` - - fmt.Print("") - fmt.Println(titleStyle.Render(title)) - - // Create persistent history - var history []string - - for { - input := prompt.Input( - "› ", - completer, - prompt.OptionPrefixTextColor(prompt.Cyan), - prompt.OptionMaxSuggestion(5), - prompt.OptionSuggestionBGColor(prompt.DefaultColor), - prompt.OptionSelectedSuggestionBGColor(prompt.DefaultColor), - prompt.OptionDescriptionBGColor(prompt.DefaultColor), - prompt.OptionSelectedDescriptionBGColor(prompt.DefaultColor), - prompt.OptionPreviewSuggestionBGColor(prompt.DefaultColor), - prompt.OptionScrollbarBGColor(prompt.DefaultColor), - prompt.OptionHistory(history), - ) - - input = strings.TrimSpace(input) - - if input == "" { - continue - } - - if input == "exit" || input == "quit" { - fmt.Println("Goodbye!") - break - } - - if input == "help" { - fmt.Println("Type 'pm help' for available PM commands.\nYou can also run shell commands directly. Type 'exit' or 'quit' to leave.") - continue - } - - if input == "title" { - fmt.Println(titleStyle.Render(title)) - continue - } - - // Add to history - history = append(history, input) - - // Check if it's a PM command (starts with "pm ") - if after, ok := strings.CutPrefix(input, "pm "); ok { - // Strip "pm " prefix and execute as PM command - pmCmd := after - pmCmd = strings.TrimSpace(pmCmd) - - if pmCmd == "" { - continue - } - - args := strings.Fields(pmCmd) - if err := commands.ExecuteWithArgs(args); err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - } - } else { - // Execute as shell command - // Save terminal state before shell command - state, _ := term.GetState(int(os.Stdin.Fd())) - - cmd := exec.Command("sh", "-c", input) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Stdin = os.Stdin - - if err := cmd.Run(); err != nil { - // Restore terminal state even on error - if state != nil { - term.Restore(int(os.Stdin.Fd()), state) - } - continue - } - - // Restore terminal state for go-prompt - if state != nil { - term.Restore(int(os.Stdin.Fd()), state) - } - } - } - - // Restore terminal state - if err := term.Restore(int(os.Stdin.Fd()), oldState); err != nil { - return fmt.Errorf("failed to restore terminal state: %w", err) - } - - return nil -} - -func completer(d prompt.Document) []prompt.Suggest { - text := d.TextBeforeCursor() - words := strings.Fields(text) - - if len(words) == 0 { - return nil - } - - if words[0] != "pm" { - suggestions := []prompt.Suggest{ - {Text: "pm", Description: "Project Management System"}, - {Text: "exit", Description: "Exit pm CLI"}, - {Text: "help", Description: "Show help information"}, - {Text: "title", Description: "Print the welcome title"}, - {Text: "git", Description: "Version control system"}, - } - - if len(words) == 0 { - return suggestions - } - - var filtered []prompt.Suggest - for _, s := range suggestions { - if strings.HasPrefix(s.Text, words[0]) { - filtered = append(filtered, s) - } - } - - return filtered - } - - // If first word is "pm", provide PM command completions - if words[0] == "pm" { - // Remove "pm" from words to get the actual command - if len(words) == 1 || (len(words) == 2 && !strings.HasSuffix(text, " ")) { - return commandSuggestions(words[1:]) - } - - // Get the PM subcommand - if len(words) >= 2 { - cmd := words[1] - return flagSuggestions(cmd, words[1:], text) - } - } - - return nil -} - -func commandSuggestions(words []string) []prompt.Suggest { - suggestions := []prompt.Suggest{ - {Text: "help", Description: "Show help information"}, - {Text: "delete", Description: "Delete an issue by ID"}, - {Text: "create", Description: "Create a new issue with title"}, - {Text: "describe", Description: "Get issue details by ID"}, - {Text: "list", Description: "List all issues"}, - } - - if len(words) == 0 { - return suggestions - } - - var filtered []prompt.Suggest - for _, s := range suggestions { - if strings.HasPrefix(s.Text, words[0]) { - filtered = append(filtered, s) - } - } - return filtered -} - -func flagSuggestions(cmd string, words []string, text string) []prompt.Suggest { - var flagSuggests []prompt.Suggest - isCompleteWord := strings.HasSuffix(text, " ") - lastWord := "" - if len(words) > 0 && !isCompleteWord { - lastWord = words[len(words)-1] - } - - switch cmd { - case "create", "add": - flagSuggests = []prompt.Suggest{ - {Text: "--desc", Description: "Issue description"}, - {Text: "--status", Description: "Issue status (open, closed, in_progress)"}, - {Text: "--type", Description: "Issue type (bug, feature, task)"}, - {Text: "--priority", Description: "Issue priority (0-5)"}, - } - return filterAndCompleteFlags(flagSuggests, lastWord, words) - - case "ls", "list", "search": - flagSuggests = []prompt.Suggest{ - {Text: "--title", Description: "Filter by title"}, - {Text: "--desc", Description: "Filter by description"}, - {Text: "--status", Description: "Filter by status (open, closed, in_progress)"}, - {Text: "--type", Description: "Filter by type (bug, feature, task)"}, - {Text: "--priority", Description: "Filter by priority (0-5)"}, - {Text: "--limit", Description: "Limit number of results"}, - } - return filterAndCompleteFlags(flagSuggests, lastWord, words) - - case "describe", "get", "read": - return issueIdSuggestions(words) - - case "delete": - return issueIdSuggestions(words) - } - - return nil -} - -func issueIdSuggestions(words []string) []prompt.Suggest { - if len(words) < 2 { - return nil - } - - // Get the partial ID being typed - partial := "" - if len(words) >= 2 { - partial = words[len(words)-1] - } - - issues, _ := commands.GetIssueCompletions(context.Background(), partial) - - var suggestions []prompt.Suggest - for _, issue := range issues { - suggestions = append(suggestions, prompt.Suggest{ - Text: issue.ID, Description: truncate.String(issue.Title, 20), - }) - } - return suggestions -} - -func filterAndCompleteFlags(suggestions []prompt.Suggest, lastWord string, words []string) []prompt.Suggest { - if len(words) >= 2 { - prevWord := words[len(words)-2] - switch prevWord { - case "-s", "--status": - return []prompt.Suggest{ - {Text: "open", Description: "Open status"}, - {Text: "closed", Description: "Closed status"}, - {Text: "in_progress", Description: "In progress status"}, - } - case "-t", "--type": - return []prompt.Suggest{ - {Text: "bug", Description: "Bug issue type"}, - {Text: "feature", Description: "Feature issue type"}, - {Text: "task", Description: "Task issue type"}, - } - case "-p", "--priority": - return []prompt.Suggest{ - {Text: "0", Description: "Lowest priority"}, - {Text: "1", Description: "Low priority"}, - {Text: "2", Description: "Medium-low priority"}, - {Text: "3", Description: "Medium priority"}, - {Text: "4", Description: "High priority"}, - {Text: "5", Description: "Highest priority"}, - } - } - } - - if lastWord == "" { - return suggestions - } - - var filtered []prompt.Suggest - for _, s := range suggestions { - if strings.HasPrefix(s.Text, lastWord) { - filtered = append(filtered, s) - } - } - return filtered -}