Documentation ¶
Index ¶
- func EvaluateNoOp[T base](t T, ctx ctx, cap string, info []byte) (resp, error)
- func EvaluateReferenced[T base](t T, ctx ctx, cap string, info []byte) (resp, error)
- func LogHandler(log logr.Logger) jsonrpc2.HandlerFunc
- type AwaitCache
- type AwaitCacheValue
- type ChainHandler
- type CmdDialer
- type DefaultHandler
- type HasLSPServiceClientBase
- type LSPServiceClientBase
- func (sc *LSPServiceClientBase) GetAllDeclarations(ctx context.Context, workspaceFolders []string, query string) []protocol.WorkspaceSymbol
- func (sc *LSPServiceClientBase) GetAllReferences(ctx context.Context, location protocol.Location) []protocol.Location
- func (sc *LSPServiceClientBase) GetDependencies(ctx context.Context) (map[uri.URI][]*provider.Dep, error)
- func (sc *LSPServiceClientBase) GetDependenciesDAG(ctx context.Context) (map[uri.URI][]provider.DepDAGItem, error)
- func (sc *LSPServiceClientBase) GetLSPServiceClientBase() *LSPServiceClientBase
- func (sc *LSPServiceClientBase) Handle(ctx context.Context, req *jsonrpc2.Request) (result interface{}, err error)
- func (sc *LSPServiceClientBase) Stop()
- type LSPServiceClientCapability
- type LSPServiceClientConfig
- type LSPServiceClientEvaluator
- type LSPServiceClientFunc
- type NoOpCondition
- type ReferencedCondition
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EvaluateNoOp ¶
A simple no-op function. Returns a blank response
func EvaluateReferenced ¶
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.
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 ¶
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
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 ¶
Create a new CmdDialer
type DefaultHandler ¶
type DefaultHandler struct{}
Default handler always 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 (*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) 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 ¶
type LSPServiceClientFunc[T HasLSPServiceClientBase] func(T, context.Context, string, []byte) (provider.ProviderEvaluateResponse, error)
Cannot have generic function type aliases, but this is still better than typing out the entire function type definition
type ReferencedCondition ¶
type ReferencedCondition struct { Referenced struct { Pattern string `yaml:"pattern"` } `yaml:"referenced"` }
Generic referenced condition