refactor: add terminal output and forms package (#1124)

- `internal/terminal`: streams and the prompting policy, interactive forms (issue, PR, review, merge, milestone), editor / pager / browser launching, JSON and `--jq` output.
- An aligned table renderer and a record renderer for human output; both strip control and escape characters from server-supplied text so titles and bodies cannot inject terminal sequences.

Reviewed-on: https://gitea.com/gitea/tea/pulls/1124
Reviewed-by: TheFox0x7 <95654+thefox0x7@noreply.gitea.com>
This commit is contained in:
bircni committed 2026-10-11 17:12:23 +00:00
1 parent 88b91faa54
commit faea86cd94
27 files changed
+1941 -1

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package terminal
import (
"context"
"errors"
"fmt"
"io"
"net/url"
"os/exec"
"runtime"
"strings"
)
// Browser opens an explicitly requested resource using a configured command.
type Browser interface {
Open(context.Context, string, string) error
}
// SystemBrowser runs the browser without a shell and routes diagnostics to stderr.
type SystemBrowser struct{ ErrOut io.Writer }
// Open validates the resource and invokes the selected browser directly.
func (b SystemBrowser) Open(ctx context.Context, resource, command string) error {
u, err := url.Parse(resource)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" || u.User != nil || strings.ContainsAny(resource, "\x00\r\n") {
return errors.New("browser requires an HTTP or HTTPS resource URL without credentials")
}
var args []string
if command == "" || command == "auto" {
switch runtime.GOOS {
case "darwin":
args = []string{"open"}
case "windows":
args = []string{"rundll32", "url.dll,FileProtocolHandler"}
default:
args = []string{"xdg-open"}
}
} else {
if command == "never" {
return errors.New("browser opening is disabled; configure browser or BROWSER")
}
var ok bool
if args, ok = commandArgs(command); !ok {
return errors.New("browser command contains malformed quoted arguments")
}
}
process := exec.CommandContext(ctx, args[0], append(args[1:], resource)...)
process.Stdout, process.Stderr = b.ErrOut, b.ErrOut
if err := process.Run(); err != nil {
if ctx.Err() != nil {
return ctx.Err()
}
return fmt.Errorf("browser could not be opened; configure browser or BROWSER: %w", err)
}
return nil
}