+++ /dev/null
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package lsp implements LSP for gopls.
-package lsp
-
-import (
- "context"
- "fmt"
- "sync"
-
- "golang.org/x/tools/internal/jsonrpc2"
- "golang.org/x/tools/internal/lsp/protocol"
- "golang.org/x/tools/internal/lsp/source"
- "golang.org/x/tools/internal/span"
- errors "golang.org/x/xerrors"
-)
-
-const concurrentAnalyses = 1
-
-// NewServer creates an LSP server and binds it to handle incoming client
-// messages on on the supplied stream.
-func NewServer(session source.Session, client protocol.Client) *Server {
- return &Server{
- delivered: make(map[span.URI]sentDiagnostics),
- gcOptimizationDetails: make(map[span.URI]struct{}),
- watchedDirectories: make(map[span.URI]struct{}),
- changedFiles: make(map[span.URI]struct{}),
- session: session,
- client: client,
- diagnosticsSema: make(chan struct{}, concurrentAnalyses),
- progress: newProgressTracker(client),
- debouncer: newDebouncer(),
- }
-}
-
-type serverState int
-
-const (
- serverCreated = serverState(iota)
- serverInitializing // set once the server has received "initialize" request
- serverInitialized // set once the server has received "initialized" request
- serverShutDown
-)
-
-func (s serverState) String() string {
- switch s {
- case serverCreated:
- return "created"
- case serverInitializing:
- return "initializing"
- case serverInitialized:
- return "initialized"
- case serverShutDown:
- return "shutDown"
- }
- return fmt.Sprintf("(unknown state: %d)", int(s))
-}
-
-// Server implements the protocol.Server interface.
-type Server struct {
- client protocol.Client
-
- stateMu sync.Mutex
- state serverState
-
- session source.Session
- clientPID int
-
- // notifications generated before serverInitialized
- notifications []*protocol.ShowMessageParams
-
- // changedFiles tracks files for which there has been a textDocument/didChange.
- changedFilesMu sync.Mutex
- changedFiles map[span.URI]struct{}
-
- // folders is only valid between initialize and initialized, and holds the
- // set of folders to build views for when we are ready
- pendingFolders []protocol.WorkspaceFolder
-
- // watchedDirectories is the set of directories that we have requested that
- // the client watch on disk. It will be updated as the set of directories
- // that the server should watch changes.
- watchedDirectoriesMu sync.Mutex
- watchedDirectories map[span.URI]struct{}
- watchRegistrationCount uint64
-
- // delivered is a cache of the diagnostics that the server has sent.
- deliveredMu sync.Mutex
- delivered map[span.URI]sentDiagnostics
-
- // gcOptimizationDetails describes the packages for which we want
- // optimization details to be included in the diagnostics. The key is the
- // directory of the package.
- gcOptimizationDetailsMu sync.Mutex
- gcOptimizationDetails map[span.URI]struct{}
-
- // diagnosticsSema limits the concurrency of diagnostics runs, which can be expensive.
- diagnosticsSema chan struct{}
-
- progress *progressTracker
-
- // debouncer is used for debouncing diagnostics.
- debouncer *debouncer
-}
-
-// sentDiagnostics is used to cache diagnostics that have been sent for a given file.
-type sentDiagnostics struct {
- id source.VersionedFileIdentity
- sorted []*source.Diagnostic
- includeAnalysis bool
- snapshotID uint64
-}
-
-func (s *Server) workDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error {
- return s.progress.cancel(ctx, params.Token)
-}
-
-func (s *Server) nonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) {
- paramMap := params.(map[string]interface{})
- if method == "gopls/diagnoseFiles" {
- for _, file := range paramMap["files"].([]interface{}) {
- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, protocol.DocumentURI(file.(string)), source.UnknownKind)
- defer release()
- if !ok {
- return nil, err
- }
-
- fileID, diagnostics, err := source.FileDiagnostics(ctx, snapshot, fh.URI())
- if err != nil {
- return nil, err
- }
- if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
- URI: protocol.URIFromSpanURI(fh.URI()),
- Diagnostics: toProtocolDiagnostics(diagnostics),
- Version: fileID.Version,
- }); err != nil {
- return nil, err
- }
- }
- if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
- URI: "gopls://diagnostics-done",
- }); err != nil {
- return nil, err
- }
- return struct{}{}, nil
- }
- return nil, notImplemented(method)
-}
-
-func notImplemented(method string) error {
- return errors.Errorf("%w: %q not yet implemented", jsonrpc2.ErrMethodNotFound, method)
-}
-
-//go:generate helper/helper -d protocol/tsserver.go -o server_gen.go -u .