summaryrefslogtreecommitdiff
path: root/internal/repl/repl.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/repl/repl.go')
-rw-r--r--internal/repl/repl.go145
1 files changed, 1 insertions, 144 deletions
diff --git a/internal/repl/repl.go b/internal/repl/repl.go
index f452351..e70be01 100644
--- a/internal/repl/repl.go
+++ b/internal/repl/repl.go
@@ -6,7 +6,6 @@ package repl
import (
"fmt"
"strings"
- "sync"
"codeberg.org/snonux/gt/internal/rpn"
@@ -22,26 +21,6 @@ type RPNState struct {
rpnCalc *rpn.RPN
}
-// executorREPL holds the REPL instance created by the executor function.
-// This is used for backward compatibility with tests that need to access RPN state
-// after calling executor(). It's not part of the main REPL architecture.
-// Thread safety: Use executorREPLOnce for lazy initialization and executorREPLMu for access.
-var executorREPL *REPL
-var executorREPLOnce sync.Once
-var executorREPLMu sync.Mutex
-
-// ResetExecutorREPL resets the executorREPL for clean test isolation.
-// This should be called between tests that use executor() and getRPNState()
-// to ensure each test starts with a fresh RPN state.
-//
-// Note: This function is intended for test use only and should not be used
-// in production code. For production use, create new REPL instances with NewREPL().
-func ResetExecutorREPL() {
- executorREPLMu.Lock()
- defer executorREPLMu.Unlock()
- executorREPL = nil
-}
-
// REPL manages the interactive command-line interface for the percentage calculator.
// It provides an interactive prompt with history, tab-completion, signal handling,
// and command processing through a chain of responsibility pattern.
@@ -190,7 +169,7 @@ func defaultCompleter(r *REPL, d prompt.Document) []prompt.Suggest {
}
var suggestions []prompt.Suggest
- for _, cmd := range builtinCommands() {
+ for _, cmd := range Commands() {
if strings.HasPrefix(strings.ToLower(cmd), strings.ToLower(text)) {
suggestions = append(suggestions, prompt.Suggest{
Text: cmd,
@@ -237,125 +216,3 @@ func RunREPL() error {
repl := NewREPL(nil, nil)
return repl.Run()
}
-
-// executor runs a calculation command and returns the result.
-// This is a package-level wrapper for backward compatibility and testing.
-// It creates a minimal REPL instance without building a prompt, allowing
-// calculation execution in non-interactive contexts.
-//
-// input: the calculation or command string to execute
-// The function processes the input through defaultExecutor, which handles
-// commands via the chain of responsibility pattern, including percentage
-// calculations, RPN expressions, and built-in commands.
-func executor(input string) {
- // Initialize executorREPL only once using sync.Once for thread-safe lazy initialization
- executorREPLOnce.Do(func() {
- vars := rpn.NewVariables()
- rpnState := &RPNState{
- vars: vars,
- rpnCalc: rpn.NewRPN(vars),
- }
-
- // Create a minimal REPL instance without building a prompt
- executorREPL = &REPL{
- ttyChecker: &TTYChecker{},
- historyMgr: NewHistoryManager(".gt_history"),
- signalHandler: NewSignalHandler(),
- commandChain: NewCommandChain(),
- rpnState: rpnState,
- }
- })
-
- // Use mutex to protect access to executorREPL during execution
- executorREPLMu.Lock()
- repl := executorREPL
- executorREPLMu.Unlock()
-
- defaultExecutor(repl, input)
-}
-
-// runRPN parses and evaluates an RPN (Reverse Polish Notation) expression.
-// This is a package-level wrapper for backward compatibility that delegates to
-// the executor's REPL runRPN method.
-//
-// input: the RPN expression to evaluate
-// Returns the result string and an error if the expression is invalid
-func runRPN(input string) (string, error) {
- executorREPLMu.Lock()
- defer executorREPLMu.Unlock()
-
- if executorREPL != nil {
- return executorREPL.rpnState.rpnCalc.ParseAndEvaluate(input)
- }
- return "", fmt.Errorf("no executor REPL available - call executor() first")
-}
-
-// getRPNState returns the RPN state from the executor's REPL.
-// This is a package-level helper for backward compatibility with tests that need
-// to access RPN state after calling executor(). It's not part of the main REPL
-// architecture.
-//
-// Returns the RPNState instance from the last executor() call, or nil if executor() hasn't been called
-func getRPNState() *RPNState {
- executorREPLMu.Lock()
- defer executorREPLMu.Unlock()
-
- if executorREPL != nil {
- return executorREPL.rpnState
- }
- return nil
-}
-
-
-
-
-
-// getHistoryPath returns the absolute path to the history file.
-// This is a package-level wrapper for backward compatibility.
-// The history file is stored in the user's home directory.
-//
-// Returns the full path to the history file, or empty string on error
-func getHistoryPath() string {
- historyMgr := NewHistoryManager(".gt_history")
- return historyMgr.Path()
-}
-
-// loadHistory loads history from the history file.
-// This is a package-level wrapper for backward compatibility that uses NewHistoryManager.
-//
-// Returns a slice of history entries, or nil if the file doesn't exist
-func loadHistory() []string {
- historyMgr := NewHistoryManager(".gt_history")
- return historyMgr.Load()
-}
-
-// saveHistory saves history to the history file.
-// This is a package-level wrapper for backward compatibility that uses NewHistoryManager.
-//
-// history: the slice of history entries to save
-// Returns an error if the file cannot be written
-func saveHistory(history []string) error {
- historyMgr := NewHistoryManager(".gt_history")
- return historyMgr.Save(history)
-}
-
-// isBuiltinCommand checks if input starts with a built-in command.
-// It performs case-insensitive matching against known built-in commands.
-//
-// input: the command string to check
-// Returns the input string and true if it starts with a built-in command,
-// or empty string and false otherwise
-func isBuiltinCommand(input string) (string, bool) {
- args := strings.Fields(input)
- if len(args) == 0 {
- return "", false
- }
-
- cmd := strings.ToLower(args[0])
- for _, builtin := range builtinCommands() {
- if cmd == builtin {
- return input, true
- }
- }
- return "", false
-}