mirror of
https://github.com/golang/go
synced 2024-11-19 02:24:41 -07:00
744a51dd88
This allows us to use the diff.ApplyEdits in tests, saving us from a different implementation. It also prepares for command lines that need to use diff features based on the results of a protocol message. Splitting content into lines is too easy to get wrong, and needs to be done correctly or the diff results make no sense. This adds the SplitLines function to the diff pacakge to do it right and then uses it everwhere we we already doing it wrong. It also makes all the diff tests external black box tests. Change-Id: I698227d5769a2bfbfd22a64ea42906b1df9268d9 Reviewed-on: https://go-review.googlesource.com/c/tools/+/171027 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
109 lines
3.1 KiB
Go
109 lines
3.1 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 {
|
|
Logger() xlog.Logger
|
|
FileSet() *token.FileSet
|
|
GetFile(ctx context.Context, uri span.URI) (File, error)
|
|
SetContent(ctx context.Context, uri span.URI, content []byte) error
|
|
}
|
|
|
|
// 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
|
|
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
|
|
}
|
|
|
|
// Package represents a Go package that has been type-checked. It maintains
|
|
// only the relevant fields of a *go/packages.Package.
|
|
type Package interface {
|
|
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)
|
|
}
|
|
|
|
// 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
|
|
}
|