base

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2024 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EvaluateNoOp

func EvaluateNoOp[T base](t T, ctx ctx, cap string, info []byte) (resp, error)

A simple no-op function. Returns a blank response

func EvaluateReferenced

func EvaluateReferenced[T base](t T, ctx ctx, cap string, info []byte) (resp, error)

EvaluateReferenced evaluates references to a given entity based on a query pattern. The function uses the provided query pattern to find references to the specified entity within the workspace, filters out references in certain directories, and returns a list of incident contexts associated with these references.

func LogHandler

func LogHandler(log logr.Logger) jsonrpc2.HandlerFunc

Logs the requests received

Types

type AwaitCache

type AwaitCache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

AwaitCache is a generic cache that allows values to be awaited until they are ready.

func NewAwaitCache

func NewAwaitCache[K comparable, V any]() *AwaitCache[K, V]

NewAwaitCache creates and returns a new AwaitCache instance.

func (*AwaitCache[K, V]) Delete

func (ac *AwaitCache[K, V]) Delete(key K)

Delete removes a key and its associated value from the cache.

func (*AwaitCache[K, V]) Get

func (ac *AwaitCache[K, V]) Get(key K) *AwaitCacheValue[V]

Get retrieves a value associated with a key. If the value doesn't exist, it creates a new one.

TODO(jsussman): Make this use RLock and RUnlock somehow

func (*AwaitCache[K, V]) Set

func (ac *AwaitCache[K, V]) Set(key K, val V)

Set sets a value associated with a key in the cache.

type AwaitCacheValue

type AwaitCacheValue[V any] struct {
	// contains filtered or unexported fields
}

AwaitCacheValue represents a value in the cache that can be awaited until it is ready.

func NewAwaitCacheValue

func NewAwaitCacheValue[V any]() *AwaitCacheValue[V]

NewAwaitCacheValue creates and returns a new AwaitCacheValue instance.

func (*AwaitCacheValue[V]) Await

func (acv *AwaitCacheValue[V]) Await() V

Await waits until the value is ready and returns it.

func (*AwaitCacheValue[V]) IsReady

func (acv *AwaitCacheValue[V]) IsReady() bool

IsReady checks if the value is ready without blocking.

func (*AwaitCacheValue[V]) SetValue

func (acv *AwaitCacheValue[V]) SetValue(value V)

SetValue sets the value of the AwaitCacheValue and signals its readiness.

type ChainHandler

type ChainHandler struct {
	Handlers []jsonrpc2.Handler
}

Executes the Handlers one after the other, back to front stack-like. Returns the first response that has error == nil

func NewChainHandler

func NewChainHandler(handlers ...jsonrpc2.Handler) *ChainHandler

Create a new ChainHandler with auto-flattening

func (*ChainHandler) Handle

func (ch *ChainHandler) Handle(ctx context.Context, req *jsonrpc2.Request) (result interface{}, err error)

Executes the Handlers one after the other, back to front stack-like. Returns the first response that has error == nil

type CmdDialer

type CmdDialer struct {
	Cmd    *exec.Cmd
	Stdin  io.WriteCloser
	Stdout io.ReadCloser
	// contains filtered or unexported fields
}

Dialers in jsonrpc2_v2 return a ReadWriteCloser that sends and receives information from the server. CmdDialer functions as a both a ReadWriteCloser to the spawned process and as a Dialer that returns itself.

NOTE: Dial should only be called once. This is because closing CmdDialer also kills the underlying process

func NewCmdDialer

func NewCmdDialer(ctx context.Context, name string, arg ...string) (*CmdDialer, error)

Create a new CmdDialer

func (*CmdDialer) Close

func (rwc *CmdDialer) Close() error

func (*CmdDialer) Dial

func (rwc *CmdDialer) Dial(ctx context.Context) (io.ReadWriteCloser, error)

CmdDialer.Dial returns itself as a CmdDialer is a ReadWriteCloser.

func (*CmdDialer) Read

func (rwc *CmdDialer) Read(p []byte) (int, error)

func (*CmdDialer) Write

func (rwc *CmdDialer) Write(p []byte) (int, error)

type DefaultHandler

type DefaultHandler struct{}

Default handler always returns jsonrpc2.ErrNotHandled for every request.

func (*DefaultHandler) Handle

func (*DefaultHandler) Handle(context.Context, *jsonrpc2.Request) (interface{}, error)

Returns jsonrpc2.ErrNotHandled for every request.

type HasLSPServiceClientBase

type HasLSPServiceClientBase interface {
	GetLSPServiceClientBase() *LSPServiceClientBase
}

For the generic methods we must convert the T to a *LSPServiceClientBase[T], so we need to make sure that it has this method. Kind of a hack

type LSPServiceClientBase

type LSPServiceClientBase struct {
	Ctx        context.Context
	CancelFunc context.CancelFunc
	Log        logr.Logger

	BaseConfig LSPServiceClientConfig

	Dialer *CmdDialer
	Conn   *jsonrpc2.Connection

	// There are some concerns about cache inconsistency when using AwaitCache, so
	// for simplicity, we should probably only get diagnostics for each file
	// exactly once.
	PublishDiagnosticsCache *AwaitCache[string, []protocol.Diagnostic]

	ServerCapabilities protocol.ServerCapabilities
	ServerInfo         *protocol.PServerInfoMsg_initialize

	TempDir string
}

Almost everything implemented to satisfy the protocol.ServiceClient interface. The only thing that's not is `Evaluate`, intentionally.

TODO(jsussman): Evaluate the merits of creating a separate ServiceClientBase that this inherits so we can talk to non-lsp things as well (for example, `yq` for yaml). This would involve doing something like extracting out `NewCmdDialer` (incorrect phraseology). Server & Client handler, look at jsonrpc2's serve_test.go

func NewLSPServiceClientBase

func NewLSPServiceClientBase(
	ctx context.Context, log logr.Logger, c provider.InitConfig,
	initializeHandler jsonrpc2.Handler,
	initializeParams protocol.InitializeParams,
) (*LSPServiceClientBase, error)

func (*LSPServiceClientBase) GetAllDeclarations

func (sc *LSPServiceClientBase) GetAllDeclarations(ctx context.Context, workspaceFolders []string, query string) []protocol.WorkspaceSymbol

Returns all top-level declaration symbols for the given query.

gopls's `workspace/symbol` only returns the *top-level declarations* in each file (see ^1). Each LSP server has different semantics for handling queries.

- gopls: https://github.com/golang/tools/blob/master/gopls/doc/features.md#symbol-queries - pylsp: https://jedi.readthedocs.io/en/latest/docs/api.html#jedi.Project.search

func (*LSPServiceClientBase) GetAllReferences

func (sc *LSPServiceClientBase) GetAllReferences(ctx context.Context, location protocol.Location) []protocol.Location

func (*LSPServiceClientBase) GetDependencies

func (sc *LSPServiceClientBase) GetDependencies(ctx context.Context) (map[uri.URI][]*provider.Dep, error)

This GetDependencies method was the one that was present in the generic-external-provider before I got my hands on it. Not too sure what it's used for. I didn't want to break anything so I just made it the default implementation.

func (*LSPServiceClientBase) GetDependenciesDAG

func (sc *LSPServiceClientBase) GetDependenciesDAG(ctx context.Context) (map[uri.URI][]provider.DepDAGItem, error)

We don't have dependencies

func (*LSPServiceClientBase) GetLSPServiceClientBase

func (sc *LSPServiceClientBase) GetLSPServiceClientBase() *LSPServiceClientBase

Method exists so that we can do generic capabilities. See `base_capabilities.go` for examples

func (*LSPServiceClientBase) Handle

func (sc *LSPServiceClientBase) Handle(ctx context.Context, req *jsonrpc2.Request) (result interface{}, err error)

func (*LSPServiceClientBase) Stop

func (sc *LSPServiceClientBase) Stop()

Shut down any spawned helper processes

type LSPServiceClientCapability

type LSPServiceClientCapability struct {
	provider.Capability
	Fn interface{}
}

Almost the same struct that we return to `analyzer-lsp` but with the added `Fn` field to reduce code duplication. We can use this struct for the Evaluator struct to call the appropriate method when queried.

type LSPServiceClientConfig

type LSPServiceClientConfig struct {
	// The name of the server. Think `yaml_language_server` not `yaml`
	LspServerName string `yaml:"lspServerName,omitempty"`

	// Where the binary of the server is. Not a URI. Passed to exec.CommandContext
	LspServerPath string `yaml:"lspServerPath,omitempty"`

	// The args of the lsp server. Passed to exec.CommandContext.
	LspServerArgs []string `yaml:"lspServerArgs,omitempty"`

	// JSON string that can get sent to the initialize request instead of the
	// computed options in the service client. Each service client can implement
	// this differently. Must be a string due to grpc not allowing nested structs.
	LspServerInitializationOptions string `yaml:"lspServerInitializationOptions,omitempty"`

	// Full URI of the workspace folders under consideration
	WorkspaceFolders []string `yaml:"workspaceFolders,omitempty"`
	// Full URI of the dependency folders under consideration. Used for ignoring
	// results from things like `referenced`
	DependencyFolders []string `yaml:"dependencyFolders,omitempty"`

	// Path to a simple binary that lists the dependencies for a given language.
	DependencyProviderPath string `yaml:"dependencyProviderPath,omitempty"`
}

The base service client configs that all subsequent configs must embed

type LSPServiceClientEvaluator

type LSPServiceClientEvaluator[T HasLSPServiceClientBase] struct {
	Parent  T
	FuncMap map[string]LSPServiceClientFunc[T]
}

Provides a generic `Evaluate` method, that calls the associated method found in the struct's FuncMap field. T should be a service client pointer

func NewLspServiceClientEvaluator

func NewLspServiceClientEvaluator[T HasLSPServiceClientBase](
	parent T, capabilities []LSPServiceClientCapability,
) (*LSPServiceClientEvaluator[T], error)

While you could implement the `Evaluate` method yourself as a massive switch-case block, it gets unwieldy after the number of capabilities grows. Additionally, whenever you add new capabilities, you have to modify things in three places: the function itself, the array of capabilities that gets advertised to the analyzer-lsp, and the `Evaluate` method. Embedding this struct knocks that down to two. (Theoretically, you could knock it down to one by defining the methods right in the array, but then you can't they can't reference each other). This is also why the LSPServiceClientCapability struct has a `Fn` field - specifically for this evaluator.

func (*LSPServiceClientEvaluator[T]) Evaluate

func (sc *LSPServiceClientEvaluator[T]) Evaluate(ctx context.Context, cap string, conditionInfo []byte) (provider.ProviderEvaluateResponse, error)

The evaluate method. Looks in the FuncMap and sees if `cap` matches. Executes the function if it does.

type LSPServiceClientFunc

Cannot have generic function type aliases, but this is still better than typing out the entire function type definition

type NoOpCondition

type NoOpCondition struct{}

Technically not necessary

type ReferencedCondition

type ReferencedCondition struct {
	Referenced struct {
		Pattern string `yaml:"pattern"`
	} `yaml:"referenced"`
}

Generic referenced condition

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL