Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions cmd/cmd_common_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
flagPrintLogsName = "print-logs"
flagDebugName = "debug"
flagDumpLogsName = "dump-logs"
flagLogoName = "logo"
)

// addJsonFlag adds the --json flag to a command.
Expand All @@ -33,3 +34,27 @@
func addNoStyleFlag(cmd *cobra.Command) {
cmd.Flags().Bool(flagNoStyleName, false, "Disable colored and styled output")
}

func addLogoFlag(cmd *cobra.Command) {
cmd.Flags().String(
flagLogoName,
"small",
"Status ASCII logo: none, small, or large (large is opt-in)",
)
}

// addSourceFlag adds the --source/-s flag to a command.
// Validation of the source value is done in PreRunE of each command.
func addSourceFlag(cmd *cobra.Command) {
cmd.Flags().StringP(flagSourceName, "s", "", "To fetch info from SOURCE")

Check failure on line 49 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / test

undefined: flagSourceName

Check failure on line 49 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / test

undefined: flagSourceName

Check failure on line 49 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / build

undefined: flagSourceName
}

// validateSourceFlag validates the --source flag value.
// Returns an error if the source is not recognized.
func validateSourceFlag(cmd *cobra.Command) error {
source, _ := cmd.Flags().GetString(flagSourceName)

Check failure on line 55 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / test

undefined: flagSourceName

Check failure on line 55 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / test

undefined: flagSourceName

Check failure on line 55 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / build

undefined: flagSourceName
if source != "" && types.ParseSource(source) == types.SourceUnknown {

Check failure on line 56 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / test

undefined: types

Check failure on line 56 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / test

undefined: types

Check failure on line 56 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / build

undefined: types
return errors.New("unknown source " + source)

Check failure on line 57 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / test

undefined: errors

Check failure on line 57 in cmd/cmd_common_flags.go

View workflow job for this annotation

GitHub Actions / build

undefined: errors
}
return nil
}
8 changes: 8 additions & 0 deletions cmd/cmd_completion_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ func StaticEcosystemCandidates() []CompletionCandidate {
}
}

func StaticStatusLogoCandidates() []CompletionCandidate {
return []CompletionCandidate{
{Value: "small", Description: "Compact logo (default)"},
{Value: "none", Description: "Hide the logo"},
{Value: "large", Description: "Full-size logo"},
}
}

// StaticSearchEcosystemCandidates returns completion candidates for search-enabled platforms (rollout set).
func StaticSearchEcosystemCandidates() []CompletionCandidate {
return []CompletionCandidate{
Expand Down
35 changes: 32 additions & 3 deletions cmd/cmd_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,30 @@
Use: "status",
Short: "Display basic information of the current server",
Args: cobra.NoArgs,
RunE: runWithErrorLogging(actionStatus),
PreRunE: func(cmd *cobra.Command, args []string) error {
logo, _ := cmd.Flags().GetString(flagLogoName)
if _, ok := tui.ParseStatusLogoMode(logo); !ok {
return fmt.Errorf("--logo must be one of none, small, large")
}
return nil
},
RunE: runWithErrorLogging(actionStatus),
}

func init() {
addJsonFlag(statusCmd)
addLongFlag(statusCmd)
addLogoFlag(statusCmd)
_ = statusCmd.RegisterFlagCompletionFunc(
flagLogoName,
func(cmd *cobra.Command, args []string, toComplete string) (
[]string,
cobra.ShellCompDirective,
) {
candidates := FilterByPrefix(StaticStatusLogoCandidates(), toComplete)
return ToCobraCompletions(candidates), cobra.ShellCompDirectiveNoFileComp
},
)
rootCmd.AddCommand(statusCmd)
}

Expand All @@ -39,7 +57,9 @@
style.PrintAsJson(ws)
}
} else {
tui.Flush(generateStatusOutput(&ws, long, noStyle))
logo, _ := cmd.Flags().GetString(flagLogoName)
logoMode, _ := tui.ParseStatusLogoMode(logo)
tui.Flush(generateStatusOutput(&ws, long, noStyle, logoMode))
}
return nil
}
Expand All @@ -48,6 +68,7 @@
data *workspace.Workspace,
longOutput bool,
noStyle bool,
logoMode tui.StatusLogoMode,
) (output *tui.Data) {
if data.Server == nil {
return &tui.Data{
Expand All @@ -59,7 +80,7 @@
}
}

output = &tui.Data{Fields: []tui.Field{}}
output = &tui.Data{Fields: []tui.Field{}, LogoMode: logoMode}
serverPlatform := data.DerivedModLoader()
modPlatforms := statusModEcosystems(data.Topology, serverPlatform)
showPlatformQualifiedMods := len(modPlatforms) > 1
Expand Down Expand Up @@ -100,11 +121,19 @@
logoEco = types.EcoVanilla
}
} else if serverPlatform.IsModding() {
logoEco = serverPlatform
}

if logoMode != tui.StatusLogoNone &&
logoEco != types.EcoBare &&

Check failure on line 128 in cmd/cmd_status.go

View workflow job for this annotation

GitHub Actions / test

undefined: types.EcoBare

Check failure on line 128 in cmd/cmd_status.go

View workflow job for this annotation

GitHub Actions / build

undefined: types.EcoBare
logoEco != types.EcoUnknown &&

Check failure on line 129 in cmd/cmd_status.go

View workflow job for this annotation

GitHub Actions / test

undefined: types.EcoUnknown

Check failure on line 129 in cmd/cmd_status.go

View workflow job for this annotation

GitHub Actions / build

undefined: types.EcoUnknown
logoEco != types.EcoAny {

Check failure on line 130 in cmd/cmd_status.go

View workflow job for this annotation

GitHub Actions / test

undefined: types.EcoAny

Check failure on line 130 in cmd/cmd_status.go

View workflow job for this annotation

GitHub Actions / build

undefined: types.EcoAny
output.Fields = append(
output.Fields,
&tui.FieldLogo{
Eco: logoEco,
NoColor: noStyle,
Mode: logoMode,
},
)
}
Expand Down
100 changes: 100 additions & 0 deletions prompt/prompt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package prompt

import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
)

func Note(title, description string) error {
if title != "" {
fmt.Println(title)
}
if description != "" {
fmt.Println(description)
}
fmt.Print("Press Enter to continue...")
_, err := readLine()
if err != nil {
return err
}
return nil
}

func Confirm(title, description, affirmative, negative string) (bool, error) {
if affirmative == "" {
affirmative = "yes"
}
if negative == "" {
negative = "no"
}

if title != "" {
fmt.Println(title)
}
if description != "" {
fmt.Println(description)
}

for {
fmt.Printf("[%s/%s]: ", affirmative, negative)
line, err := readLine()
if err != nil {
return false, err
}
switch strings.ToLower(strings.TrimSpace(line)) {
case "y", "yes", strings.ToLower(affirmative):
return true, nil
case "n", "no", strings.ToLower(negative):
return false, nil
default:
fmt.Println("Please answer yes or no.")
}
}
}

func Select[T any](title string, options []T, format func(T) string) (T, error) {
var zero T
if len(options) == 0 {
return zero, fmt.Errorf("no options available")
}

if title != "" {
fmt.Println(title)
}
for i, option := range options {
fmt.Printf("%d) %s\n", i+1, format(option))
}

for {
fmt.Printf("Select [1-%d]: ", len(options))
line, err := readLine()
if err != nil {
return zero, err
}
choice, err := strconv.Atoi(strings.TrimSpace(line))
if err != nil || choice < 1 || choice > len(options) {
fmt.Println("Invalid selection.")
continue
}
return options[choice-1], nil
}
}

func readLine() (string, error) {
reader := bufio.NewReader(os.Stdin)
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
trimmed := strings.TrimSpace(line)
if trimmed != "" {
return trimmed, nil
}
}
return "", err
}
return strings.TrimSpace(line), nil
}
62 changes: 62 additions & 0 deletions tui/assets/ansi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import re
import html
import argparse

COLOR_PATTERN = re.compile(
r'\[color=#([0-9a-fA-F]{6})\](.*?)\[/color\]',
re.DOTALL
)


def hex_to_rgb(hex_color):
r = int(hex_color[0:2], 16)
g = int(hex_color[2:4], 16)
b = int(hex_color[4:6], 16)
return r, g, b


def convert_to_ansi(text):
text = html.unescape(text)

def repl(match):
hex_color = match.group(1)
content = match.group(2)

if not content:
return ""

r, g, b = hex_to_rgb(hex_color)

ansi_start = f"\033[38;2;{r};{g};{b}m"
ansi_end = "\033[0m"

return ansi_start + content + ansi_end

return COLOR_PATTERN.sub(repl, text)


def strip_other_tags(text):
text = re.sub(r'\[/?size.*?\]', '', text)
text = re.sub(r'\[/?font.*?\]', '', text)
text = re.sub(r'<.*?>', '', text)
return text


def main():
parser = argparse.ArgumentParser(
description="Convert BBCode color text to ANSI escape codes")
parser.add_argument("input", help="input file")

args = parser.parse_args()

with open(args.input, "r", encoding="utf-8") as f:
data = f.read()

data = strip_other_tags(data)
ansi = convert_to_ansi(data)

print(ansi, end="")


if __name__ == "__main__":
main()
Loading
Loading