111 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			3.2 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
 | 
						|
	BuiltinPackage() *ast.Package
 | 
						|
	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
 | 
						|
	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
 | 
						|
}
 | 
						|
 | 
						|
// 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
 | 
						|
}
 |