Files
claude-plugin-runescape/scripts/rsw/internal/cmd/skill.go
2026-03-05 01:13:19 -06:00

145 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cmd
import (
"fmt"
"strings"
"github.com/runescape-wiki/rsw/internal/extract"
"github.com/runescape-wiki/rsw/internal/render"
"github.com/runescape-wiki/rsw/internal/wiki"
"github.com/spf13/cobra"
)
func newSkillCmd() *cobra.Command {
var levelRange string
cmd := &cobra.Command{
Use: "skill <name>",
Short: "Look up skill training methods",
Long: `Fetches training guide information for a skill. Optionally filter
to a specific level range.
With --ironman, emphasizes training methods viable without GE access.
Examples:
rsw osrs skill mining
rsw rs3 skill "prayer" --level 50-70
rsw osrs skill slayer --ironman`,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
skillName := args[0]
wikiClient := wiki.NewClient(GameBaseURL())
trainingTitle := capitalizeFirst(strings.ToLower(skillName)) + " training"
page, err := wikiClient.GetPage(trainingTitle)
if err != nil {
page, err = wikiClient.GetPage(capitalizeFirst(strings.ToLower(skillName)))
if err != nil {
return fmt.Errorf("failed to fetch skill page: %w", err)
}
}
if Raw() {
fmt.Println(page.Wikitext)
return nil
}
md := render.New()
md.H1(fmt.Sprintf("%s Training Guide", page.Title))
if Ironman() {
md.P("*Showing methods suitable for ironman accounts (no GE access).*")
}
if len(page.Sections) > 0 {
md.H2("Contents")
for _, s := range page.Sections {
if s.Level == "2" {
md.Bullet(s.Line)
}
}
md.Newline()
}
if levelRange != "" {
found := false
for _, s := range page.Sections {
if strings.Contains(strings.ToLower(s.Line), strings.ToLower(levelRange)) ||
sectionMatchesLevelRange(s.Line, levelRange) {
idx := 0
fmt.Sscanf(s.Index, "%d", &idx)
if idx > 0 {
sectionPage, err := wikiClient.GetPageSection(page.Title, idx)
if err == nil {
plain := extract.ExtractPlainText(sectionPage.Wikitext)
if strings.TrimSpace(plain) != "" {
md.H2(s.Line)
md.P(plain)
found = true
}
}
}
}
}
if !found {
md.P(fmt.Sprintf("*No section found matching level range %q. Showing full guide.*", levelRange))
renderFullGuide(md, page, wikiClient)
}
} else {
renderFullGuide(md, page, wikiClient)
}
fmt.Print(md.String())
return nil
},
}
cmd.Flags().StringVar(&levelRange, "level", "", "Filter to a level range (e.g., '50-70')")
return cmd
}
func renderFullGuide(md *render.Builder, page *wiki.ParsedPage, client *wiki.Client) {
for _, s := range page.Sections {
if s.Level != "2" {
continue
}
idx := 0
fmt.Sscanf(s.Index, "%d", &idx)
if idx <= 0 {
continue
}
sectionPage, err := client.GetPageSection(page.Title, idx)
if err != nil {
continue
}
plain := extract.ExtractPlainText(sectionPage.Wikitext)
if strings.TrimSpace(plain) != "" {
md.H2(s.Line)
md.P(plain)
}
}
}
func sectionMatchesLevelRange(heading, levelRange string) bool {
h := strings.ToLower(heading)
h = strings.ReplaceAll(h, "", "-")
h = strings.ReplaceAll(h, "—", "-")
h = strings.ReplaceAll(h, " ", "")
lr := strings.ToLower(levelRange)
lr = strings.ReplaceAll(lr, " ", "")
return strings.Contains(h, lr)
}
func capitalizeFirst(s string) string {
if s == "" {
return s
}
return strings.ToUpper(s[:1]) + s[1:]
}
func init() {
RegisterCommand(newSkillCmd)
}