go/internal/lsp/source/view.go
Ian Cottrell 0e55654012 internal/lsp: add shutdown handling
We correcly cancel all background tasks and drop all active views when
the server is asked to shut down now.
This was mostly to support the command line being able to exit cleanly

Change-Id: Iff9f5ab51572aad5e3245dc01aa87b00dcd47963
Reviewed-on: https://go-review.googlesource.com/c/tools/+/174940
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
2019-05-15 23:16:32 +00:00

123 lines
3.5 KiB
Go

// 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 source
import (
"context"
"go/ast"
"go/token"
"go/types"
"strings"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/lsp/diff"
"golang.org/x/tools/internal/lsp/xlog"
"golang.org/x/tools/internal/span"
)
// View abstracts the underlying architecture of the package using the source
// package. The view provides access to files and their contents, so the source
// package does not directly access the file system.
type View interface {
Name() string
Folder() span.URI
Logger() xlog.Logger
FileSet() *token.FileSet
BuiltinPackage() *ast.Package
GetFile(ctx context.Context, uri span.URI) (File, error)
SetContent(ctx context.Context, uri span.URI, content []byte) error
BackgroundContext() context.Context
Config() packages.Config
SetEnv([]string)
Shutdown(ctx context.Context)
}
// File represents a Go source file that has been type-checked. It is the input
// to most of the exported functions in this package, as it wraps up the
// building blocks for most queries. Users of the source package can abstract
// the loading of packages into their own caching systems.
type File interface {
URI() span.URI
View() View
GetAST(ctx context.Context) *ast.File
GetFileSet(ctx context.Context) *token.FileSet
GetPackage(ctx context.Context) Package
GetToken(ctx context.Context) *token.File
GetContent(ctx context.Context) []byte
// GetActiveReverseDeps returns the active files belonging to the reverse
// dependencies of this file's package.
GetActiveReverseDeps(ctx context.Context) []File
}
// Package represents a Go package that has been type-checked. It maintains
// only the relevant fields of a *go/packages.Package.
type Package interface {
PkgPath() string
GetFilenames() []string
GetSyntax() []*ast.File
GetErrors() []packages.Error
GetTypes() *types.Package
GetTypesInfo() *types.Info
GetTypesSizes() types.Sizes
IsIllTyped() bool
GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*Action, error)
GetImport(pkgPath string) Package
}
// TextEdit represents a change to a section of a document.
// The text within the specified span should be replaced by the supplied new text.
type TextEdit struct {
Span span.Span
NewText string
}
// DiffToEdits converts from a sequence of diff operations to a sequence of
// source.TextEdit
func DiffToEdits(uri span.URI, ops []*diff.Op) []TextEdit {
edits := make([]TextEdit, 0, len(ops))
for _, op := range ops {
s := span.New(uri, span.NewPoint(op.I1+1, 1, 0), span.NewPoint(op.I2+1, 1, 0))
switch op.Kind {
case diff.Delete:
// Delete: unformatted[i1:i2] is deleted.
edits = append(edits, TextEdit{Span: s})
case diff.Insert:
// Insert: formatted[j1:j2] is inserted at unformatted[i1:i1].
if content := strings.Join(op.Content, ""); content != "" {
edits = append(edits, TextEdit{Span: s, NewText: content})
}
}
}
return edits
}
func EditsToDiff(edits []TextEdit) []*diff.Op {
iToJ := 0
ops := make([]*diff.Op, len(edits))
for i, edit := range edits {
i1 := edit.Span.Start().Line() - 1
i2 := edit.Span.End().Line() - 1
kind := diff.Insert
if edit.NewText == "" {
kind = diff.Delete
}
ops[i] = &diff.Op{
Kind: kind,
Content: diff.SplitLines(edit.NewText),
I1: i1,
I2: i2,
J1: i1 + iToJ,
}
if kind == diff.Insert {
iToJ += len(ops[i].Content)
} else {
iToJ -= i2 - i1
}
}
return ops
}