summaryrefslogtreecommitdiff
path: root/internal/repl/help.go
blob: 9796644e1c632e33e6f39d77dd6d7802eb6935bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Paul Buetow

package repl

import (
	"fmt"
	"slices"
	"strings"
)

// GetHelp returns the formatted help text for a topic.
// If topic is empty, it returns the general help overview.
func GetHelp(topic string) string {
	if topic == "" {
		return getGeneralHelp()
	}

	// Look up by operator name or alias
	topic = strings.ToLower(topic)
	t, ok := helpByTopic[topic]
	if !ok {
		t, ok = helpByAlias[topic]
	}
	if !ok {
		return fmt.Sprintf("No help for %q.\n\nType 'help' for an overview, or 'help categories' to list all topics.", topic)
	}
	if t.Render != nil {
		return t.Render()
	}
	return formatTopic(t)
}

// GetAllTopics returns a sorted list of all help topic names.
func GetAllTopics() []string {
	topics := make([]string, 0, len(helpByTopic))
	for op := range helpByTopic {
		topics = append(topics, op)
	}
	slices.Sort(topics)
	return topics
}

// GetCompletionTopics returns all help topics suitable for tab completion.
// Includes operator names and aliases from all registered HelpTopic entries.
func GetCompletionTopics() []string {
	seen := make(map[string]struct{})
	var topics []string

	// Add all operator names (skip "help" itself — no need to complete help help)
	for op, t := range helpByTopic {
		if op == "help" {
			continue
		}
		topics = append(topics, op)
		seen[op] = struct{}{}
		// Add aliases
		for _, a := range t.Aliases {
			if _, ok := seen[a]; !ok {
				topics = append(topics, a)
				seen[a] = struct{}{}
			}
		}
	}
	slices.Sort(topics)
	return topics
}

// getGeneralHelp returns the overview help text.
func getGeneralHelp() string {
	var sb strings.Builder

	sb.WriteString("gt - Reverse Polish Notation (RPN) Calculator\n\n")
	sb.WriteString("Help Topics:\n")
	sb.WriteString("  help [topic]       Show help for a specific topic\n")
	sb.WriteString("  help categories    List all available help topics by category\n\n")

	sb.WriteString("REPL Commands:\n")
	for _, op := range helpByCat["REPL"] {
		t := helpByTopic[op]
		sb.WriteString(fmt.Sprintf("  %-12s %s\n", op, t.Description))
	}

	sb.WriteString("\nArithmetic Operators:\n")
	for _, op := range helpByCat["Arithmetic"] {
		t := helpByTopic[op]
		sb.WriteString(fmt.Sprintf("  %-8s %s\n", op, t.Description))
	}

	sb.WriteString("\nComparison Operators:\n")
	for _, op := range helpByCat["Comparison"] {
		t := helpByTopic[op]
		sb.WriteString(fmt.Sprintf("  %-8s %s\n", op, t.Description))
	}

	sb.WriteString("\nStack Operators:\n")
	for _, op := range helpByCat["Stack"] {
		t := helpByTopic[op]
		sb.WriteString(fmt.Sprintf("  %-12s %s\n", op, t.Description))
	}

	sb.WriteString("\nHyper (n-ary) Operators:\n")
	for _, op := range helpByCat["Hyper"] {
		t := helpByTopic[op]
		sb.WriteString(fmt.Sprintf("  %-8s %s\n", op, t.Description))
	}

	sb.WriteString("\nVariables and Constants:\n")
	for _, cat := range []string{"Variables", "Constants"} {
		for _, op := range helpByCat[cat] {
			t := helpByTopic[op]
			sb.WriteString(fmt.Sprintf("  %-16s %s\n", op, t.Description))
		}
	}

	sb.WriteString("\nKeyboard Shortcuts:\n")
	sb.WriteString("  Ctrl+A         Go to beginning of line\n")
	sb.WriteString("  Ctrl+E         Go to end of line\n")
	sb.WriteString("  Ctrl+L         Clear screen\n")
	sb.WriteString("  Ctrl+D         Exit / delete character\n")
	sb.WriteString("  Up/Down        History navigation\n")
	sb.WriteString("  Tab            Auto-complete\n")

	sb.WriteString("\nUse 'help <topic>' for details on any operator or command.\n")
	sb.WriteString("Use 'help categories' to see all available topics.\n")

	return sb.String()
}

// formatTopic returns the detailed help for a single HelpTopic.
func formatTopic(t *HelpTopic) string {
	var sb strings.Builder

	sb.WriteString(fmt.Sprintf("Topic:    %s (Category: %s)\n", t.Operator, t.Category))
	if len(t.Aliases) > 0 {
		sb.WriteString(fmt.Sprintf("Aliases:  %s\n", strings.Join(t.Aliases, ", ")))
	}
	sb.WriteString(fmt.Sprintf("Usage:    %s\n", t.Usage))
	sb.WriteString(fmt.Sprintf("Desc:     %s\n", t.Description))

	sb.WriteString("\nExamples:\n")
	for _, ex := range t.Examples {
		sb.WriteString(fmt.Sprintf("  %s\n", ex))
	}

	return sb.String()
}