Skip to content

Commit

Permalink
Rewrite the CLI with ANSI colors and more idiomatic Swift CLI code
Browse files Browse the repository at this point in the history
  • Loading branch information
marcusziade committed Oct 29, 2024
1 parent 5f5eb13 commit fd7dee2
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 165 deletions.
14 changes: 14 additions & 0 deletions Sources/StarCraftCLI/ANSIColor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
enum ANSIColor {
static let reset = "\u{001B}[0m"
static let bold = "\u{001B}[1m"

// Race Colors
static let protoss = "\u{001B}[38;2;255;223;0m" // Golden yellow
static let terran = "\u{001B}[38;2;0;156;255m" // Bright blue
static let zerg = "\u{001B}[38;2;163;53;238m" // Purple

// Accent Colors
static let neon = "\u{001B}[38;2;0;255;255m" // Cyan
static let warning = "\u{001B}[38;2;255;69;0m" // Red-Orange
static let success = "\u{001B}[38;2;50;205;50m" // Lime Green
}
18 changes: 18 additions & 0 deletions Sources/StarCraftCLI/ActivePlayersCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation
import StarCraftKit

struct ActivePlayersCommand: Command {
let api: StarCraftAPI

var description: String {
return "Fetch active players"
}

func execute() async throws {
let response = try await api.allPlayers().activePlayers
print("\(ANSIColor.terran)Active Players:\(ANSIColor.reset)")
response.forEach { player in
print("\(ANSIColor.neon)\(ANSIColor.reset) \(player.name)")
}
}
}
4 changes: 4 additions & 0 deletions Sources/StarCraftCLI/Command.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
protocol Command {
var description: String { get }
func execute() async throws
}
16 changes: 16 additions & 0 deletions Sources/StarCraftCLI/LiveTournamentsCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Foundation
import StarCraftKit

struct LiveTournamentsCommand: Command {
let api: StarCraftAPI

var description: String {
return "Fetch tournaments with live support"
}

func execute() async throws {
let response = try await api.allTournaments()
let liveSupported = response.liveSupportedTournaments
print("\(ANSIColor.protoss)Live Supported Tournaments: \(liveSupported.count)\(ANSIColor.reset)")
}
}
16 changes: 16 additions & 0 deletions Sources/StarCraftCLI/OngoingMatchesCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Foundation
import StarCraftKit

struct OngoingMatchesCommand: Command {
let api: StarCraftAPI

var description: String {
return "Fetch ongoing matches"
}

func execute() async throws {
let response = try await api.allMatches()
let ongoingMatches = response.ongoingMatches
print("\(ANSIColor.zerg)Ongoing Matches: \(ongoingMatches.count)\(ANSIColor.reset)")
}
}
16 changes: 16 additions & 0 deletions Sources/StarCraftCLI/OngoingTournamentsCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Foundation
import StarCraftKit

struct OngoingTournamentsCommand: Command {
let api: StarCraftAPI

var description: String {
return "Fetch ongoing tournaments"
}

func execute() async throws {
let response = try await api.allTournaments()
let ongoing = response.ongoingTournaments
print("\(ANSIColor.protoss)Ongoing Tournaments: \(ongoing.count)\(ANSIColor.reset)")
}
}
75 changes: 75 additions & 0 deletions Sources/StarCraftCLI/StarCraftCLI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Foundation
import StarCraftKit

@main
struct StarCraftCLI {
private let api: StarCraftAPI
private var commands: [String: Command] = [:]

init() {
guard let token = ProcessInfo.processInfo.environment["PANDA_TOKEN"] else {
print("\(ANSIColor.warning)Error: PANDA_TOKEN environment variable not set\(ANSIColor.reset)")
exit(1)
}

self.api = StarCraftAPI(token: token)
setupCommands()
}

private mutating func setupCommands() {
commands = [
"-ap": ActivePlayersCommand(api: api),
"-lt": LiveTournamentsCommand(api: api),
"-om": OngoingMatchesCommand(api: api),
"-ot": OngoingTournamentsCommand(api: api),
"-ut": UpcomingTournamentsCommand(api: api)
]
}

static func main() {
let cli = StarCraftCLI()
let arguments = CommandLine.arguments

if arguments.count > 1 {
cli.execute(command: arguments[1])
} else {
cli.printInstructions()
}
}

private func execute(command: String) {
guard let cmd = commands[command] else {
print("\(ANSIColor.warning)Unknown command: \(command)\(ANSIColor.reset)")
return
}

Task.detached(priority: .medium) {
do {
try await cmd.execute()
exit(0)
} catch {
print("\(ANSIColor.warning)Error: \(error)\(ANSIColor.reset)")
exit(1)
}
}

RunLoop.current.run()
}

private func printInstructions() {
print()
print("\(ANSIColor.neon)\(ANSIColor.bold)╔══════════════════════════════════╗")
print("║ Welcome to StarCraftCLI II ║")
print("╚══════════════════════════════════╝\(ANSIColor.reset)")
print()
print("\(ANSIColor.terran)Available Commands:\(ANSIColor.reset)")
commands.forEach { cmd, implementation in
print("\(ANSIColor.protoss)\(cmd)\(ANSIColor.reset) \(implementation.description)")
}
print()
print("\(ANSIColor.warning)Note: You must provide a valid PANDA_TOKEN environment variable\(ANSIColor.reset)")
print()
print("\(ANSIColor.neon)Usage:\(ANSIColor.reset) swift run StarCraftCLI <command>")
print("\(ANSIColor.neon)Example:\(ANSIColor.reset) swift run StarCraftCLI -ap")
}
}
42 changes: 42 additions & 0 deletions Sources/StarCraftCLI/UpcomingTournamentsCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Foundation
import StarCraftKit

struct UpcomingTournamentsCommand: Command {
let api: StarCraftAPI

var description: String {
return "Fetch upcoming tournaments"
}

func execute() async throws {
let response = try await api.allTournaments()
let upcoming = response.upcomingTournaments

print("\(ANSIColor.protoss)Upcoming Tournaments:\(ANSIColor.reset)\n")

for tournament in upcoming {
print("\(ANSIColor.neon)═══════════════════════════════════════\(ANSIColor.reset)")
print("\(ANSIColor.terran)Name:\(ANSIColor.reset) \(tournament.name)")
print("\(ANSIColor.terran)Start Date:\(ANSIColor.reset) \(DateFormatter.prettyFormatter.string(from: tournament.beginAt))")
print("\(ANSIColor.terran)End Date:\(ANSIColor.reset) \(DateFormatter.prettyFormatter.string(from: tournament.endAt))")
print("\(ANSIColor.terran)League:\(ANSIColor.reset) \(tournament.league?.name ?? "Unknown")")
print("\(ANSIColor.terran)Game:\(ANSIColor.reset) \(tournament.videogame?.name ?? "Unknown")")
print("\(ANSIColor.terran)Prize Pool:\(ANSIColor.reset) \(tournament.prizepool ?? "Unknown")")

if let matches = tournament.matches {
print("\n\(ANSIColor.zerg)Matches:\(ANSIColor.reset)")
for match in matches {
print("\(ANSIColor.neon)\(ANSIColor.reset) \(match.name)")
print(" Status: \(match.status)")
if let opponents = match.opponents {
print(" \(ANSIColor.protoss)VS\(ANSIColor.reset)")
for opponent in opponents {
print(" \(ANSIColor.terran)\(ANSIColor.reset) \(opponent.opponent.name)")
}
}
}
}
print()
}
}
}
10 changes: 0 additions & 10 deletions Sources/StarCraftCLI/activePlayers.swift

This file was deleted.

11 changes: 0 additions & 11 deletions Sources/StarCraftCLI/liveSupportedGames.swift

This file was deleted.

38 changes: 0 additions & 38 deletions Sources/StarCraftCLI/main.swift

This file was deleted.

11 changes: 0 additions & 11 deletions Sources/StarCraftCLI/ongoingMatches.swift

This file was deleted.

11 changes: 0 additions & 11 deletions Sources/StarCraftCLI/ongoingTournaments.swift

This file was deleted.

19 changes: 0 additions & 19 deletions Sources/StarCraftCLI/printInstructions.swift

This file was deleted.

65 changes: 0 additions & 65 deletions Sources/StarCraftCLI/upcomingTournaments.swift

This file was deleted.

0 comments on commit fd7dee2

Please sign in to comment.