diff --git a/cli/main.go b/cli/main.go index 5dc447f..42867e0 100644 --- a/cli/main.go +++ b/cli/main.go @@ -308,18 +308,42 @@ func runConsumer(productID, query, langName string, noContribute bool) error { } fmt.Fprintln(os.Stderr, "") - for _, link := range links { + + var selectedURI string + if isTerminal() && len(links) > 1 { + link, err := pickArchitecture(links) + if err != nil { + return err + } name := urlFilename(link.URI) - fmt.Fprintf(os.Stderr, " %s\n", name) - fmt.Fprintf(os.Stderr, " %s\n", strings.Repeat("─", len(name))) - fmt.Println(link.URI) // stdout — stays clean for piping - fmt.Fprintln(os.Stderr, "") + fmt.Fprintf(os.Stderr, "\n %s\n", name) + fmt.Fprintf(os.Stderr, " %s\n\n", strings.Repeat("─", len(name))) + fmt.Println(link.URI) + selectedURI = link.URI + } else { + for _, link := range links { + name := urlFilename(link.URI) + fmt.Fprintf(os.Stderr, " %s\n", name) + fmt.Fprintf(os.Stderr, " %s\n", strings.Repeat("─", len(name))) + fmt.Println(link.URI) // stdout — stays clean for piping + fmt.Fprintln(os.Stderr, "") + } + if len(links) == 1 { + selectedURI = links[0].URI + } } if !noContribute { fmt.Fprintln(os.Stderr, " ✓ Shared with MSDL Web App (https://msdl.tech-latest.com/)") fmt.Fprintln(os.Stderr, " Opt out: --no-contribute") fmt.Fprintln(os.Stderr, "") + } + + if isTerminal() && selectedURI != "" { + postFetchMenu(selectedURI) + } + + if !noContribute { // Wait up to 5s for the contribution to complete before process exit. done := make(chan struct{}) go func() { wg.Wait(); close(done) }() @@ -359,6 +383,9 @@ func runEval(slug string) error { if len(links) == 1 { fmt.Println(links[0].URL) + if isTerminal() { + postFetchMenu(links[0].URL) + } return nil } @@ -377,6 +404,10 @@ func runEval(slug string) error { if err != nil { return err } - fmt.Println(links[n-1].URL) + selected := links[n-1].URL + fmt.Println(selected) + if isTerminal() { + postFetchMenu(selected) + } return nil } diff --git a/cli/picker.go b/cli/picker.go index baeb830..c1cd10b 100644 --- a/cli/picker.go +++ b/cli/picker.go @@ -5,6 +5,8 @@ import ( "fmt" "io" "os" + "os/exec" + "runtime" "strconv" "strings" ) @@ -76,3 +78,79 @@ func pickEvalProduct(products []EvalProduct) (EvalProduct, error) { } return products[n-1], nil } + +func isTerminal() bool { + fi, err := os.Stdin.Stat() + if err != nil { + return false + } + return fi.Mode()&os.ModeCharDevice != 0 +} + +func pickArchitecture(links []DownloadLink) (DownloadLink, error) { + fmt.Fprintln(os.Stderr, "Select architecture:") + for i, l := range links { + label := l.Architecture + if label == "" { + label = fmt.Sprintf("link %d", i+1) + } + fmt.Fprintf(os.Stderr, " %2d. %s\n", i+1, label) + } + fmt.Fprint(os.Stderr, "\nChoice: ") + n, err := parseChoice(os.Stdin, len(links)) + if err != nil { + return DownloadLink{}, err + } + return links[n-1], nil +} + +func openInBrowser(rawURL string) error { + var cmd *exec.Cmd + switch runtime.GOOS { + case "windows": + cmd = exec.Command("cmd", "/c", "start", "", rawURL) + case "darwin": + cmd = exec.Command("open", rawURL) + default: + cmd = exec.Command("xdg-open", rawURL) + } + return cmd.Run() +} + +func copyToClipboard(text string) error { + var cmd *exec.Cmd + switch runtime.GOOS { + case "windows": + cmd = exec.Command("cmd", "/c", "clip") + case "darwin": + cmd = exec.Command("pbcopy") + default: + if _, err := exec.LookPath("xclip"); err == nil { + cmd = exec.Command("xclip", "-selection", "clipboard") + } else { + cmd = exec.Command("xsel", "--clipboard", "--input") + } + } + cmd.Stdin = strings.NewReader(text) + return cmd.Run() +} + +func postFetchMenu(uri string) { + fmt.Fprint(os.Stderr, "\n [O] Open in browser [C] Copy to clipboard [Enter] Exit\n > ") + scanner := bufio.NewScanner(os.Stdin) + if !scanner.Scan() { + return + } + switch strings.ToLower(strings.TrimSpace(scanner.Text())) { + case "o": + if err := openInBrowser(uri); err != nil { + fmt.Fprintln(os.Stderr, " Could not open browser:", err) + } + case "c": + if err := copyToClipboard(uri); err != nil { + fmt.Fprintln(os.Stderr, " Could not copy to clipboard:", err) + } else { + fmt.Fprintln(os.Stderr, " ✓ Copied to clipboard") + } + } +}