Vscode: Interactive Diagnostics

Created on 6 Dec 2018  Â·  23Comments  Â·  Source: microsoft/vscode

Problem

JS and TS diagnostic messages can get quite large, especially when dealing with frameworks like Vue or react. The TS team has worked to significantly improve and shorten diagnostic messages, including replacing complex type information with ..., however there are still cases where you need to see the full type information. Right now, we have to staticly choose to expand the additional information or not. They would like the user to be able to interactively expand types within a diagnostic

In addition, the overall diagnostic experience could be improved. Two areas identified talking with the TS team:

  • Syntax coloring of inline code in diagnostics
  • Go to definition in diagnostics

Refs

11847

Desired User Experience

Consider a diagnostic message T<...>. We would like the ... to be something like a link. Clicking it would expand the diagnostic message to T<Array<...>>, which itself contains another expandable link

Requirements

The main focus is on being able dynamically to expand sections of a diagnostic. We need new VS Code API support for this and then will need languages to adopt this API. However, I think the other two features should be considered while designing the new diagnostics API as they are likely something we would like to support and will influence overall api design

For expansion, we want to be able to:

  • Mark arbitrary spans within a diagnostics as expandable
  • Lazily compute these expansions, i.e. don't resolve the expansions ahead of time
  • Allow expansions to contain other expansions
  • Show a progress indicator of some kind while an expansion is being resolved

Many of these features also make sense for quick info hovers

api languages-diagnostics under-discussion

Most helpful comment

Please allow these to be expanded somehow. It has become VERY frustrating working with types now in typescript. I'm wasting so much time trying to get everything to work with the different intellisense features, and not being able to copy and paste complete types, or even read them properly has become VERY frustrating and time consuming. PLEASE PLEASE PLEASE add SOME way (even just a command) to show the full type without any abbreviations.

One problem is that I don't even know which type is being repeated or if more than one is being repeated. A type variable layout would be more clear.

I'm used to hacking other peoples code, so I am perfectly capable of building an extension or changing the source code, I just don't want to have to do that with everything I use. Why can't the tools just do what they're supposed to do and get out of the way?

Problem solved!

See https://github.com/microsoft/vscode/issues/64566#issuecomment-590140308

All 23 comments

DiagnosticPart Api sketch

This api sketch proposes making diagnostic messages a list of parts. Parts would be joined together to form the message rendered in the editor:

interface TextDiagnosticPart {
    readonly type: 'text';

    /**
     * Text rendered in the editor
     */
    readonly text: string;
}

interface ExpansionDiagnosticPart {
    readonly type: 'expansion';

    /**
     * Contents rendered for the expansion, such as the text `...`
     */
    readonly contents: ReaonlyArray<DiagnosticPart>;

    /**
     * Lazily resolves the diagnostics.
     * 
     * The could also be implemented using a provider or commands.
     */
    expand(): Thenable<ReaonlyArray<DiagnosticPart>>;
}

type DiagnosticPart = TextDiagnosticPart | ExpansionDiagnosticPart;

The diagnostic type would then become:

export class Diagnostic {
    ...

    message: string | ReadonlyArray<DiagnosticPart>;

     ...
}

Extensions

  • The idea of diagnostic parts could be easily extended to clickable links and code:
interface ClickableDiagnosticPart {
    readonly type: 'clickable';

    /**
     * Contents rendered in the diagnostics 
     */
    readonly contents: ReaonlyArray<DiagnosticPart>;

    /**
     * Command executed on click
     */
    readonly command: Command
}

interface CodeDiagnosticPart {
    readonly type: 'code';

    /**
     * Language to use for syntax highlighting
     */
    readonly language: string

    /**
     * Code rendered in the editor
     */
    readonly contents: ReaonlyArray<DiagnosticPart>;
}
  • We could also use a more generic name like MessagePart (needs better name) so that parts could also be used in hovers and other UI locations

/cc @sandy081, @jrieken, @dbaeumer, @DanielRosenwasser, @weswigham, @amcasey

FYI @minestarks

Probably worth noting that for the syntax highlighting extension bit, it's very possible that syntax highlighted and linked/expanded ranges overlap; so them being mutually exclusive parts would seem to prevent that.

@weswigham Good point. I've updated CodeDiagnosticPart to potentially handle nesting better. One difficult thing about colorization is that the snippets may not actually be valid code. T<...> for example would colorize T as a variable.other.constant instead of as a type if we reused the js/ts grammar.

In the TS / editor sync today, we also discussed a proposal that would allow specific spans to marked as code or as expandable, something like:

interface DiagnosticMessage {
    /**
     * Text rendered in the editor
     */
    readonly text: string;

    /**
     * Ranges within the text that can be expanded.
     */
    readonly expandableRanges?: Range[];

    /**
     * Ranges within the text that should be rendered as code
     */
    readonly codeRanges?: { range: Range, language: string } [];
}

Keeping the range correct after expansion happens could get tricky

Is this inventing our own markup language? How about using markdown as proposed by @mjbvz here:
https://github.com/Microsoft/vscode/issues/54272

Rendered markdown could be used to implement hyperlinks (though you'd need to ensure file urls with locations work fine in markdown link tags) and if you're lucky syntax highlighting (although what's keeping the editor highlighting and the markdown highlighting consistent?) but I don't think it covers the expandable lazy ranges (the original request) - unless that markdown support goes all the way to full blown html/js support.

It's might also worth noting that for the syntax highlighting part, we'd likely be trying to colorize things in specific contexts, so in addition to the standard markdown language selector, you'd also need to be able to somehow specify a specific tmLanguage rule to start in (instead of the root rule - this way our types get syntax highlighted as types and not statements). So in that regard, getting pre-classified spans (a la quickinfo) back from the language service might be easier than messing with picking apart tmLanguage rulesets; but I'm not the most familiar with them, so I'm not sure.

unless that markdown support goes all the way to full blown html/js support.

Yeah, good point... We could experiment with commands. We already support command-links and we could have a special command that replaces the link text...

you'd also need to be able to somehow specify a specific tmLanguage rule to start in (instead of the root rule - this way our types get syntax highlighted

The markdown rendering picks up any language that's registered (by extensions). So it would require some special code-chunk-language so that MD will use the grammar that came with that language.

Stepping back a bit: The idea is to keep of all this in the editor hover, right? So make that smarter and a bit more interactive? I am asking because the hover is easy to dismiss and maybe not the best place for a UX in which the user invests time configuring its state.

My 2 cents, I would not have asynchronosity in error message which might not have good UX especially in Hovers. Why does this needs to be async first of all Is it expensive to compute complete message?

Also not a big fan of having UI semantics. My first step would be to use MD string. BTW, Is not the related information can be used to show more information? I think we do not restrict this to be used only for multi-diagnostics but also for adding more information.

Why does this needs to be async first of all Is it expensive to compute complete message?

It can be, yes. Our typesystem has the ability to generate new types by mapping old ones, so you can get very complex or large (anonymous) types with a very short sequence of type operators. And when those appear in errors, well... Things can get difficult to grok very quickly since there's simply too much to print - today we're forced to truncate the output, but making it explorable just like how dotting off the object can reveal more info would go a long way toward making it easier to work with.

My 2 cents, I would not have asynchronosity in error message which might not have good UX especially in Hovers.

Ignoring hover over red squiggles for a moment, errors still appear in the problems window and the f8 error bar as well, both of which are much more persistent. I'd think persisting the hover text as it is updated is an extension of those two.

BTW, Is not the related information can be used to show more information?

Nope - in this case the lazy querying is key to making it work. It allows us to gradually expose/generate the shape of complex types as requested, and only the parts requested. We _actually_ have the ability to construct infinitely deep anonymous types - today we cut these off after printing one level of the type with a ..., but being able to expand these to an arbitrary depth as needed would be very nice. We do use related info where we can - it just doesn't help in complex type display/type truncation cases. (And secondarily would be a gratuitious way to "linkify" all the references in the types in an error, TBH - very nonlocal)

Stepping back a bit: The idea is to keep of all this in the editor hover, right? So make that smarter and a bit more interactive? I am asking because the hover is easy to dismiss and maybe not the best place for a UX in which the user invests time configuring its state.

What I was hoping was that diagnostic state was synchronized between the problems window/the f8 error bars/hover strings between full refreshes. That way you _can_ expand within the hover if you want (then go back to it and still see it expanded), but also explore in the other places errors are displayed. In our meeting, someone mentioned that eclipse has the ability to copy things like individual diagnostics (plus stack traces and more) into a project context pane to allow them to persist and be inspected, which could work, too, but is maybe less continuous an experience than just being able to interact with a diagnostic anywhere you see it.

adding @misolori - call for diagnostics UX ideas

Here's the most minimal API for this we could have on the vscode side:

  1. Make Diagnostic::message a markdown string
  2. In the diagnostic messages, allow hyperlinks of the form:

    some text [...](command:editor.expandDiagnostic?_typescript.resolveDiagnostic,123) and more text
    
  3. The editor.expandDiagnostic command is a special VS Code command that delegates out to another command to handle the actual expansion. In this case, it would invoke the _typescript.resolveDiagnostic command with the diagnostic object and the expansion id 123

  4. _typescript.resolveDiagnostic would return a promise to a MarkdownString. VS Code would then replace the original editor.expandDiagnostic link with the rendered string

A few things with this approach:

  1. This would let you use other markdown features like bolds and italics.
  2. Can we improve this so we don't need the command indirection?
  3. Commands don't have good cancellation semantics
  4. This is pretty VS Code specific. TypeScript would still likely want a diagnostic structure api closer to the one I originally proposed.
  5. This approach doesn't address inline syntax highlighting. That's not possible to do in markdown as far as I know

_typescript.resolveDiagnostic would return a promise to a MarkdownString. VS Code would then replace the original editor.expandDiagnostic link with the rendered string

In case TypeScript already knows the omitted text behind [...] it could just add it as argument, [...](command:md.expand?FOO). That would prevent extra commands and round trips.

This would let you use other markdown features like bolds and italics.

Yes. My POV is that it's just like Hover and editor decorations and I believe people can build cool things with it, see GitLens. Sure, there is a risk of folks turning us into a Christmas tree but then I don't use such an extension. We can also consider disabling certain markdown features, e.g. tables or images, in certain places.

This is pretty VS Code specific. TypeScript would still likely want a diagnostic structure api closer to the one I originally proposed.

Haha - better VS Code specific extension API than TypeScript specific extension API. Honestly, the proposal smells very TypeScript-tailored and we should first circle in other languages with complex error messages, maybe rust-lang or lean.

I think there should be a way to automatically expand all of the three dots when selecting the text, I use this shortcut:

Ctrl+K Ctrl+I Hover, Ctrl + A select all Ctrl+C copy

And when I select all I want the whole type, not the abbreviated form. In past I could use that to get the whole type of any JSON object pasted to VSCode, but this is not possible anymore.

Please allow these to be expanded somehow. It has become VERY frustrating working with types now in typescript. I'm wasting so much time trying to get everything to work with the different intellisense features, and not being able to copy and paste complete types, or even read them properly has become VERY frustrating and time consuming. PLEASE PLEASE PLEASE add SOME way (even just a command) to show the full type without any abbreviations.

One problem is that I don't even know which type is being repeated or if more than one is being repeated. A type variable layout would be more clear.

I'm used to hacking other peoples code, so I am perfectly capable of building an extension or changing the source code, I just don't want to have to do that with everything I use. Why can't the tools just do what they're supposed to do and get out of the way?

Problem solved!

See https://github.com/microsoft/vscode/issues/64566#issuecomment-590140308

I see at the top that this can be staticly chosen, but I have no idea how to do that. Is it a setting?

This is a really annoying issue; honestly there is never a time when I don't want to see the whole thing. Optimize for readability? How is it readable to only see a small part of the relevant information?

Would really really like to see this become a setting that was easy to tweak :-( it would save me a lot of time right now with what I'm working on

Problem solved!

noErrorTruncation: true

At some point someone pointed out the TypeScript tsconfig.json setting compilerOptions.noErrorTruncation. This in fact seems to solve the problem.

@Arlen22 It doesn't work.

image

// from https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/intro-to-tweet-json
let foo = {
  "text": "My added comments to this Tweet ---> https:\/\/t.co\/LinkToTweet",
  "user": {
    "screen_name": "TweetQuoter"
  },
  "quoted_status": {
    "text": "original message",
    "user": {
      "screen_name": "OriginalTweeter"
    },
    "place": {      
    },
    "entities": {      
    },
    "extended_entities": {      
    }
  },
  "place": {    
  },
    "entities": {
      "hashtags": [

      ],
      "urls": [
        {
          "url": "https://t.co/W1FqVrsjQk",
          "expanded_url": "https://twittercommunity.com/t/rt-with-comment-aka-quote-tweets-now-may-have-media-attached-across-twitter-apis/125539",
          "display_url": "twittercommunity.com/t/rt-with-comm…",
          "unwound": {
            "url": "https://twittercommunity.com/t/rt-with-comment-aka-quote-tweets-now-may-have-media-attached-across-twitter-apis/125539",
            "status": 200,
            "title": "RT with comment, aka Quote Tweets, now may have media attached across Twitter APIs",
            "description": "Today we’re announcing a new feature that allows userspeople on Twitter to add a GIF, video, or photo to their Retweet with comments, aka Quote Tweets. Developers will start to see additional media metadata included in the payload for Quote Tweets. Quote Tweets with media will be rendered very similarly to Tweets with media across our APIs. This rendering is an addition to the existing media field, so this should not be a breaking change for application owners, if they are already ingesting med..."
          },
          "indices": [
            162,
            185
          ]
        },
        {
          "url": "https://t.co/lXs26mCkIl",
          "expanded_url": "https://twitter.com/TwitterSupport/status/1125479034513645569",
          "display_url": "twitter.com/TwitterSupport…",
          "indices": [
            186,
            209
          ]
        }
      ],
      "user_mentions": [

      ],
      "symbols": [

      ],
      "media": [
        {
          "id": 1125490782532657153,
          "id_str": "1125490782532657153",
          "indices": [
            210,
            233
          ],
          "media_url": "http://pbs.twimg.com/tweet_video_thumb/D56L51LV4AEEC8-.jpg",
          "media_url_https": "https://pbs.twimg.com/tweet_video_thumb/D56L51LV4AEEC8-.jpg",
          "url": "https://t.co/T9MBCHZWcD",
          "display_url": "pic.twitter.com/T9MBCHZWcD",
          "expanded_url": "https://twitter.com/TwitterDev/status/1125490788736032770/photo/1",
          "type": "animated_gif",
          "video_info": {
            "aspect_ratio": [
              101,
              165
            ],
            "variants": [
              {
                "bitrate": 0,
                "content_type": "video/mp4",
                "url": "https://video.twimg.com/tweet_video/D56L51LV4AEEC8-.mp4"
              }
            ]
          },
          "sizes": {
            "thumb": {
              "w": 150,
              "h": 150,
              "resize": "crop"
            },
            "small": {
              "w": 202,
              "h": 330,
              "resize": "fit"
            },
            "large": {
              "w": 202,
              "h": 330,
              "resize": "fit"
            },
            "medium": {
              "w": 202,
              "h": 330,
              "resize": "fit"
            }
          }
        }
      ]
    },
    "extended_entities": {
      "media": [
        {
          "id": 1125490782532657153,
          "id_str": "1125490782532657153",
          "indices": [
            210,
            233
          ],
          "media_url": "http://pbs.twimg.com/tweet_video_thumb/D56L51LV4AEEC8-.jpg",
          "media_url_https": "https://pbs.twimg.com/tweet_video_thumb/D56L51LV4AEEC8-.jpg",
          "url": "https://t.co/T9MBCHZWcD",
          "display_url": "pic.twitter.com/T9MBCHZWcD",
          "expanded_url": "https://twitter.com/TwitterDev/status/1125490788736032770/photo/1",
          "type": "animated_gif",
          "video_info": {
            "aspect_ratio": [
              101,
              165
            ],
            "variants": [
              {
                "bitrate": 0,
                "content_type": "video/mp4",
                "url": "https://video.twimg.com/tweet_video/D56L51LV4AEEC8-.mp4"
              }
            ]
          },
          "sizes": {
            "thumb": {
              "w": 150,
              "h": 150,
              "resize": "crop"
            },
            "small": {
              "w": 202,
              "h": 330,
              "resize": "fit"
            },
            "large": {
              "w": 202,
              "h": 330,
              "resize": "fit"
            },
            "medium": {
              "w": 202,
              "h": 330,
              "resize": "fit"
            }
          }
        }
      ]
    }
  };

The bug to track is this: https://github.com/microsoft/TypeScript/issues/26238

I am also looking for a way to access "computed types" I've posted on StackOverflow about it here. It would be nice to have better tooling / understanding about what a type is, and I'd personally like a CLI tool that could give me a glimpse, rather then trying to get VSCode to show everything in a tooltip on hover.

same issue + 1

Somewhat related is my recently-closed-as-out-of-scope suggestion of being able to cmd-click on types in the tooltip to dig into those types (like you can in Eclipse). That request is also about having "links" within the tooltip.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

VitorLuizC picture VitorLuizC  Â·  3Comments

shanalikhan picture shanalikhan  Â·  3Comments

philipgiuliani picture philipgiuliani  Â·  3Comments

biij5698 picture biij5698  Â·  3Comments

NikosEfthias picture NikosEfthias  Â·  3Comments