package completion import ( "context" "errors" "fmt" "sync" ) var ErrInvalidRequest = errors.New("invalid completion request") // 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"` } // Item 对应一个补全候选项。 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"` } // Response 是补全结果集合。 type Response struct { Items []Item `json:"items"` IsIncomplete bool `json:"isIncomplete"` } // Client 抽象 LSP 客户端所需的最小能力。 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 } // Service 负责文档生命周期同步(didOpen/didChange)与补全调用。 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), } } // Complete 根据 URI 的历史状态决定发送 didOpen 或 didChange,再请求补全。 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 } // validateRequest 做基础参数校验,避免向 LSP 发送非法请求。 func validateRequest(req Request) error { if req.URI == "" { return ErrInvalidRequest } if req.Line < 0 || req.Character < 0 { return ErrInvalidRequest } return nil }