This commit is contained in:
2026-02-15 15:55:49 +08:00
commit 23decb8687
32 changed files with 3822 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
package completion
import (
"context"
"errors"
"fmt"
"sync"
)
var ErrInvalidRequest = errors.New("invalid completion request")
type Request struct {
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
}