1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package lsp implements LSP for gopls.
13 "golang.org/x/tools/internal/jsonrpc2"
14 "golang.org/x/tools/internal/lsp/protocol"
15 "golang.org/x/tools/internal/lsp/source"
16 "golang.org/x/tools/internal/span"
17 errors "golang.org/x/xerrors"
20 const concurrentAnalyses = 1
22 // NewServer creates an LSP server and binds it to handle incoming client
23 // messages on on the supplied stream.
24 func NewServer(session source.Session, client protocol.Client) *Server {
26 diagnostics: map[span.URI]*fileReports{},
27 gcOptimizationDetails: make(map[span.URI]struct{}),
28 watchedGlobPatterns: make(map[string]struct{}),
29 changedFiles: make(map[span.URI]struct{}),
32 diagnosticsSema: make(chan struct{}, concurrentAnalyses),
33 progress: newProgressTracker(client),
34 debouncer: newDebouncer(),
41 serverCreated = serverState(iota)
42 serverInitializing // set once the server has received "initialize" request
43 serverInitialized // set once the server has received "initialized" request
47 func (s serverState) String() string {
51 case serverInitializing:
53 case serverInitialized:
58 return fmt.Sprintf("(unknown state: %d)", int(s))
61 // Server implements the protocol.Server interface.
63 client protocol.Client
68 session source.Session
71 // notifications generated before serverInitialized
72 notifications []*protocol.ShowMessageParams
74 // changedFiles tracks files for which there has been a textDocument/didChange.
75 changedFilesMu sync.Mutex
76 changedFiles map[span.URI]struct{}
78 // folders is only valid between initialize and initialized, and holds the
79 // set of folders to build views for when we are ready
80 pendingFolders []protocol.WorkspaceFolder
82 // watchedGlobPatterns is the set of glob patterns that we have requested
83 // the client watch on disk. It will be updated as the set of directories
84 // that the server should watch changes.
85 watchedGlobPatternsMu sync.Mutex
86 watchedGlobPatterns map[string]struct{}
87 watchRegistrationCount int
89 diagnosticsMu sync.Mutex
90 diagnostics map[span.URI]*fileReports
92 // gcOptimizationDetails describes the packages for which we want
93 // optimization details to be included in the diagnostics. The key is the
94 // directory of the package.
95 gcOptimizationDetailsMu sync.Mutex
96 gcOptimizationDetails map[span.URI]struct{}
98 // diagnosticsSema limits the concurrency of diagnostics runs, which can be
100 diagnosticsSema chan struct{}
102 progress *progressTracker
104 // debouncer is used for debouncing diagnostics.
107 // When the workspace fails to load, we show its status through a progress
108 // report with an error message.
109 criticalErrorStatusMu sync.Mutex
110 criticalErrorStatus *workDone
113 func (s *Server) workDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error {
114 return s.progress.cancel(ctx, params.Token)
117 func (s *Server) nonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) {
119 case "gopls/diagnoseFiles":
120 paramMap := params.(map[string]interface{})
121 for _, file := range paramMap["files"].([]interface{}) {
122 snapshot, fh, ok, release, err := s.beginFileRequest(ctx, protocol.DocumentURI(file.(string)), source.UnknownKind)
128 fileID, diagnostics, err := source.FileDiagnostics(ctx, snapshot, fh.URI())
132 if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
133 URI: protocol.URIFromSpanURI(fh.URI()),
134 Diagnostics: toProtocolDiagnostics(diagnostics),
135 Version: fileID.Version,
140 if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
141 URI: "gopls://diagnostics-done",
145 return struct{}{}, nil
147 return nil, notImplemented(method)
150 func notImplemented(method string) error {
151 return errors.Errorf("%w: %q not yet implemented", jsonrpc2.ErrMethodNotFound, method)
154 //go:generate helper/helper -d protocol/tsserver.go -o server_gen.go -u .