Skip to content

Extension API for Inline Values #105690

Closed
Closed

Description

Today the "Show Inline Values" feature of VS Code's debugger is based on a generic implementation in the VS Code core and provides neither customisability through settings, nor extensibility via extensions.

As a consequence, it is not a perfect fit for all languages (e.g. #101797) and sometimes even shows incorrect values because it doesn't understand the scope regions of the underlying language.

This features asks for an extension API that either replaces the built-in implementation completely or allows to replace parts of the implementation with custom code.

Activity

  1. weinand commented on Aug 30, 2020

    @weinand
    ContributorAuthor

    The current generic implementation works as follows:

    • in a debug session VS Code considers only the source of the focused stack frame for showing inline values.
    • VS Code's internal tokenizer is used to find all variables in the source (without understanding scope regions of the language).
    • the potential variables are looked up in the VARIABLE views and for successful matches the value is shown inline in the editor.

    This implementation is lightweight and scales well because:

    • instead of a full language parser or AST the implementation piggybacks on the results of the tokenizer.
    • finding the variable values piggybacks on the already fetched variable values available in the VARIABLE view.
    • any false positives of the tokenizer are easily eliminated because there will be no matching variables in the VARIABLES view.

    Problems:

  2. weinand commented on Aug 31, 2020

    @weinand
    ContributorAuthor

    A first attempt for designing an extension API for inline values tried to use a similar approach as done for the debug hover with the EvaluatableExpressionProvider. In the debug hover case the provider returns an expression for a source location typically determined by the mouse, and then this expression is evaluated by the debug adapter and the result is presented in a hover window.

    For the "inline values" feature we tried to reuse the EvaluatableExpressionProvider by introducing a second method that takes a source line number as input and returns an array of {name, expressions} pairs. VS Code would evaluate the expression by the debug adapter and the present the name with the value in the editor at the end of the line.

    A prototype based on this approach showed two problem areas:

    • sending multiple "evaluate" requests for every source line to the debug adapter can be slow and affects the stepping performance significantly.
    • Since the language tokenizer is not available in extensions, implementing an EvaluatableExpressionProvider from scratch is difficult. The only realistic way to get this done is by making the EvaluatableExpressionProvider a companion to a language server so that it has access to the parser or AST.
  3. weinand commented on Jan 12, 2021

    @weinand
    ContributorAuthor

    During debugging VS Code's "Inline Values" feature shows the value of variables "inline" in the editor:

    inline_values

    (see https://code.visualstudio.com/updates/v1_9#_inline-variable-values-in-source-code)

    Today the "Show Inline Values" feature of VS Code's debugger is based on a single, generic implementation in the VS Code core and provides neither customisability through settings, nor extensibility via extensions.

    The proposal is a first attempt to create an extension API for inline values.

    Proposal:

    The new API is basically a new provider that returns the "Inline values" information (a string) for specific lines of a document.

    But there is a twist:
    The current "closed" implementation is pretty fast because it relies on the internal tokenizer and looks up values in the Variables view's model. Since extensions do not yet have access to those mechanisms, they are somewhat handicapped today. For that reason, I've introduced the InlineValueContext and InlineValueDescriptor which makes it possible to surface additional information on input (in the InlineValueContext), and additional evaluation strategies when returning values (by returning new types of InlineValueDescriptors).

    /**
     * The inline values provider interface defines the contract between extensions and the VS Code inline values feature.
     * In this contract the provider returns inline value information for a given document range
     * and VS Code shows this information in the editor at the end of lines.
     */
    export interface InlineValuesProvider {
    
        /**
         * Provide "inline value" information for a given document and range.
         * VS Code calls this method whenever debugging stops in the given document.
         * The returned inline values information is rendered in the editor at the end of lines.
         *
         * @param document The document for which the inline values information is needed.
         * @param context A bag containing contextual information like the current location.
         * @param token A cancellation token.
         * @return An array of InlineValueDescriptors or a thenable that resolves to such. The lack of a result can be
         * signaled by returning `undefined` or `null`.
         */
        provideInlineValues(document: TextDocument, context: InlineValueContext, token: CancellationToken): ProviderResult<InlineValueDescriptor[]>;
    }
    
    /**
     * An open ended information bag passed to the inline value provider.
     * A minimal context containes just the document location where the debugger has stopped.
     * Additional optional information might be scope information or variables and their values.
     */
    export interface InlineValueContext {
        /**
         * The document location where execution has stopped.
         * Typically this is used as the end position of the range where inline values are shown.
         */
        position: Position;
    
        // ... more to come, e.g. Scope information or variable/value candidate information
    }
    
    /**
     * Inline value information can exist in multiple forms. The simplest is a direct string value (class InlineValue).
     * A more complex one is an evaluatable expression.
     * The InlineValueDescriptor is just an OR-type of all current and future inline value types.
     */
    export type InlineValueDescriptor = InlineValue;
    
    /**
     * An InlineValue represents the value (string) that is shown in the editor at the end of a specific line.
     */
    export class InlineValue {
        /**
         * The document's line where to show the inline value.
         */
        readonly line: number;
        /**
         * The value to be shown for the line.
         */
        readonly value: string;
        /**
         * Creates a new InlineValue object.
         *
         * @param line The document line where to show the inline value.
         * @param value The value to be shown for the line.
         */
        constructor(line: number, value: string);
    }
    
    export namespace languages {
    
        /**
         * Register a provider that returns inline values for text documents.
         * In the active debug session VS Code shows this information in the editor at the end of lines.
         *
         * If multiple providers are registered for a language, inline values are concatenated.
         *
         * @param selector A selector that defines the documents this provider is applicable to.
         * @param provider An inline values provider.
         * @return A [disposable](#Disposable) that unregisters this provider when being disposed.
         */
        export function registerInlineValuesProvider(selector: DocumentSelector, provider: InlineValuesProvider): Disposable;
    }
  4. gjsjohnmurray commented on Jan 12, 2021

    @gjsjohnmurray
    Contributor

    InlineValue doc talks about range and expression, yet its properties are named line and value 😕

  5. weinand commented on Jan 12, 2021

    @weinand
    ContributorAuthor

    John Murray (@gjsjohnmurray) thanks for spotting this.

  6. 22 remaining items

  7. weinand commented on Mar 16, 2021

    @weinand
    ContributorAuthor

    Proposed API for the Inline Values Provider.

    Since the last API discussion a frameId attribute has been added to the open-ended InlineValueContext object.

    /**
     * A value-object that contains contextual information when requesting inline values from a InlineValuesProvider.
     */
    export interface InlineValueContext {
    
      /**
       * The stack frame (as a DAP Id) where the execution has stopped.
       */
      readonly frameId: number;
    
      /**
       * The document range where execution has stopped.
       * Typically the end position of the range denotes the line where the inline values are shown.
       */
      readonly stoppedLocation: Range;
    }
  8. weinand commented on Mar 16, 2021

    @weinand
    ContributorAuthor

    The InlineValuesProvider API has been finalized and will appear in the next Insiders.

  9. weinand commented on Mar 22, 2021

    @weinand
    ContributorAuthor

    In this milestone we've finalised the API without changing it. So the test-plan item from the previous milestone still covers it.

  10. testforstephen commented on Mar 23, 2021

    @testforstephen

    The API looks good. Here are some feedbacks about the implementation.

    1. We want to use the viewport to crop the results in cases where there is a large list of variables. But the viewPort parameter from provideInlineValues API never changes when i scroll the editor.
      For example, in my test case the initial viewport range is L80 ~ L126, and it doesn't change when i scroll up.
    Screen.Recording.2021-03-23.at.15.34.55.mov
    1. When Java debugger uses InlineValuesProvider to provide inline debugging feature, the user still needs to manually enable the user setting "debug.inlineValues" to get the feature. Is this by design?

    2. When the user uses the "Set Value" feature to update the variables, the inline values are not refreshed.

    image

  11. weinand commented on Mar 23, 2021

    @weinand
    ContributorAuthor

    Jinbo Wang (@testforstephen) thanks for the feedback.

    I've created issues #119559, #119560, #119564 for it.

  12. locked and limited conversation to collaborators on Apr 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

apiapi-finalizationdebugDebug viewlet, configurations, breakpoints, adapter issuesfeature-requestRequest for new features or functionalityinsiders-releasedPatch has been released in VS Code Insiderson-testplanrelease-notesRelease notes issues

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions