blob: fd39e144d870a0ddbcf0395c8f7aae438ed57c7a (
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
|
package lsp
import (
"sync"
"time"
)
// chatService owns the in-editor chat subsystem that used to be inlined on
// Server. It tracks editor input activity (used by the completion debounce
// gate) and reaches back into the Server (via srv) for shared infrastructure
// such as configuration, LLM clients, document access and edit dispatch.
//
// Pulling this out of Server keeps the chat detection/history/command logic
// cohesive and gives the input-activity clock its own small mutex instead of
// piggy-backing on Server.mu.
type chatService struct {
srv *Server
activityMu sync.RWMutex
lastInput time.Time
}
// newChatService constructs the chat subsystem bound to srv.
func newChatService(srv *Server) *chatService {
return &chatService{srv: srv}
}
// markActivity records that the editor just sent input. The completion
// debounce gate uses this timestamp to decide how long to wait before issuing
// an LLM request.
func (c *chatService) markActivity() {
c.activityMu.Lock()
c.lastInput = time.Now()
c.activityMu.Unlock()
}
// lastActivity returns the most recent input timestamp (zero if none yet).
func (c *chatService) lastActivity() time.Time {
c.activityMu.RLock()
defer c.activityMu.RUnlock()
return c.lastInput
}
// chatSvc returns the chat subsystem, lazily constructing it for the bare
// Server literals used in some tests. Production code always has it wired up
// by NewServer.
func (s *Server) chatSvc() *chatService {
if s.chat == nil {
s.chat = newChatService(s)
}
return s.chat
}
|