package completion import ( "context" "errors" "fmt" "sync" ) var ErrInvalidRequest = errors.New("invalid completion request") type Request struct { Language string `json:"language,omitempty"` SessionID string `json:"sessionId,omitempty"` URI string `json:"uri"` Text string `json:"text"` Line int `json:"line"` Character int `json:"character"` } type Item struct { Label string `json:"label"` Kind int `json:"kind,omitempty"` Detail string `json:"detail,omitempty"` Documentation string `json:"documentation,omitempty"` InsertText string `json:"insertText,omitempty"` SortText string `json:"sortText,omitempty"` FilterText string `json:"filterText,omitempty"` } type Response struct { Items []Item `json:"items"` IsIncomplete bool `json:"isIncomplete"` } type Client interface { DidOpen(ctx context.Context, uri, text string, version int) error DidChange(ctx context.Context, uri, text string, version int) error Completion(ctx context.Context, uri string, line, character int) (Response, error) } type documentState struct { version int } type Service struct { client Client mu sync.Mutex documents map[string]*documentState } func NewService(client Client) *Service { return &Service{ client: client, documents: make(map[string]*documentState), } } func (s *Service) Complete(ctx context.Context, req Request) (Response, error) { if err := validateRequest(req); err != nil { return Response{}, err } s.mu.Lock() defer s.mu.Unlock() state, opened := s.documents[req.URI] if !opened { if err := s.client.DidOpen(ctx, req.URI, req.Text, 1); err != nil { return Response{}, fmt.Errorf("didOpen failed: %w", err) } s.documents[req.URI] = &documentState{version: 1} } else { nextVersion := state.version + 1 if err := s.client.DidChange(ctx, req.URI, req.Text, nextVersion); err != nil { return Response{}, fmt.Errorf("didChange failed: %w", err) } state.version = nextVersion } resp, err := s.client.Completion(ctx, req.URI, req.Line, req.Character) if err != nil { return Response{}, fmt.Errorf("completion failed: %w", err) } return resp, nil } func validateRequest(req Request) error { if req.URI == "" { return ErrInvalidRequest } if req.Line < 0 || req.Character < 0 { return ErrInvalidRequest } return nil }