summaryrefslogtreecommitdiff
path: root/internal/hexaiaction/action_handler.go
blob: 8da90ea138a380f7adfaf65932419a1ce2d8817b (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
package hexaiaction

import (
	"context"
	"fmt"
	"io"
	"sync"

	"codeberg.org/snonux/hexai/internal/appconfig"
)

type actionRequest struct {
	parts          InputParts
	cfg            actionConfig
	client         chatDoer
	stderr         io.Writer
	selectedCustom *appconfig.CustomAction
}

// ActionHandler executes one tmux action kind.
type ActionHandler interface {
	Execute(context.Context, actionRequest) (string, error)
}

// CodeActionHandler is kept as a compatibility name for tmux code-action handlers.
type CodeActionHandler = ActionHandler

type actionHandlerFunc func(context.Context, actionRequest) (string, error)

func (f actionHandlerFunc) Execute(ctx context.Context, req actionRequest) (string, error) {
	return f(ctx, req)
}

type actionHandlerRegistry struct {
	mu       sync.RWMutex
	handlers map[ActionKind]ActionHandler
}

func newActionHandlerRegistry() *actionHandlerRegistry {
	return &actionHandlerRegistry{handlers: make(map[ActionKind]ActionHandler)}
}

func (r *actionHandlerRegistry) register(kind ActionKind, handler ActionHandler) {
	if kind == "" {
		panic("hexaiaction: cannot register empty action kind")
	}
	if handler == nil {
		panic(fmt.Sprintf("hexaiaction: cannot register nil handler for %q", kind))
	}

	r.mu.Lock()
	defer r.mu.Unlock()
	if _, exists := r.handlers[kind]; exists {
		panic(fmt.Sprintf("hexaiaction: handler already registered for %q", kind))
	}
	r.handlers[kind] = handler
}

func (r *actionHandlerRegistry) lookup(kind ActionKind) (ActionHandler, bool) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	handler, ok := r.handlers[kind]
	return handler, ok
}

func (r *actionHandlerRegistry) snapshot() map[ActionKind]ActionHandler {
	r.mu.RLock()
	defer r.mu.RUnlock()
	handlers := make(map[ActionKind]ActionHandler, len(r.handlers))
	for kind, handler := range r.handlers {
		handlers[kind] = handler
	}
	return handlers
}

var actionHandlers = newActionHandlerRegistry()

func registerActionHandler(kind ActionKind, handler ActionHandler) {
	actionHandlers.register(kind, handler)
}

func lookupActionHandler(kind ActionKind) (ActionHandler, bool) {
	return actionHandlers.lookup(kind)
}

func codeActionHandlers() map[ActionKind]CodeActionHandler {
	return actionHandlers.snapshot()
}