microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
163.01k stars 28.79k forks source link

Interactive Diagnostics #64566

Open mjbvz opened 5 years ago

mjbvz commented 5 years ago

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:

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:

Many of these features also make sense for quick info hovers

mjbvz commented 5 years ago

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

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>;
}
mjbvz commented 5 years ago

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

amcasey commented 5 years ago

FYI @minestarks

weswigham commented 5 years ago

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.

mjbvz commented 5 years ago

@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

jrieken commented 5 years ago

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

weswigham commented 5 years ago

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.

weswigham commented 5 years ago

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.

jrieken commented 5 years ago

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.

sandy081 commented 5 years ago

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.

weswigham commented 5 years ago

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.

jrieken commented 5 years ago

adding @misolori - call for diagnostics UX ideas

mjbvz commented 5 years ago

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
jrieken commented 5 years ago

_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.

Ciantic commented 5 years ago

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.

Arlen22 commented 4 years ago

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

Arlen22 commented 4 years ago

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

taxilian commented 4 years ago

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

Arlen22 commented 4 years ago

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.

Ciantic commented 4 years ago

@Arlen22 It doesn't work.

image

```typescript // 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

reggi commented 4 years ago

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.

lake2 commented 3 years ago

same issue + 1

plaa commented 3 years ago

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.

ghost commented 2 years ago

I found https://github.com/intellij-rust/intellij-rust/pull/4217 through https://github.com/microsoft/vscode/issues/16221#issuecomment-518658249 and it seems to be doing almost the same thing (it expands all the way with just 1 click). I would imagine it being similar to that except having the option to advance 1 step at a time?

danielo515 commented 2 years ago

What I'm doing meanwhile is to use simplify from type fest to wrap big types

It successfully expands the type on VSCode and I can freely scroll it.

jonlepage commented 2 years ago

am also look a way to get something like on hover image

instead of this

image

i tried ctrl, alt on hover but not work, any tips to extends full alias definition on hover ?.

zen0wu commented 2 years ago

can we prioritize this, we eagerly need this feature to expand all the complex types in our codebase.

i'm currently doing https://github.com/Microsoft/TypeScript/issues/26238#issuecomment-672086446, but that's undesired because sometimes i don't want to expand the full type.

205g0 commented 1 year ago

@weswigham @jrieken any news on this issue?

dreit-p commented 1 year ago

We have been waiting for any solution for 5 years now, let us know are you considering it? This problem is really annoying and limiting us

starball5 commented 1 year ago

Related: #94679 and microsoft/TypeScript#35601.

Related on Stack Overflow:

bombillazo commented 1 year ago

Right now it's like dangling a steak in front of a canine; as a dev seeing the inferred type in the tooltip and knowing VS Code can expose the complete type yet not being able to copy or extract it in any way... This would be the most effective feature to help us avoid having to manually setup up types from a JSON payload or code-gen'ing our types, especially for those that are combinations of other types.

aprilmintacpineda commented 1 year ago

It would be nice if we can click on the ellipses or more then we can see some more.

nabilfreeman commented 1 year ago

This is actually not a VSCode problem but a TypeScript problem.

Proof:

1) Create a very long type that displays ... 15 more ... when you hover it 2) Deliberately mis-assign it, for example const foo: VeryLongType = {} missing required properties or something like that 3) Run npx tsc

You'll see even in your terminal TypeScript collapses the type and outputs ... 15 more ....

But I would also like to see this fixed, because I often need to copy some complex computed types from one project to another, and this would save me a lot of chore work.

To fix this you can patch the TypeScript node module in your project (to at least get terminal output), or patch the TypeScript node module that VSCode uses.

More information here:

https://github.com/microsoft/TypeScript/issues/35601#issuecomment-921752554

vennson commented 3 months ago

Long term solution by @extremegf

in vscode

  1. Using Ctrl+P, Go to node_modules/typescript/lib/tsserver.js
  2. Find line var defaultMaximumTruncationLength = 160
  3. Change it to 1000 or value of your choosing.
  4. Open Ctrl+Shift+P menu, select TypeScript: Select TypeScript Version...
  5. Ensure it's set to Use Workspace Version
  6. Full restart VSCode - reloading workspace is not enough.
  7. Verify that ... abbreviations are gone from type hints.

PS.

Before: with ...

image

After: You can also drag the bottom border

image
boylett commented 5 days ago

Have written a quick patcher that runs automatically after installing new dependencies or updates using a post script.

  1. Add the following to scripts in package.json:

    "postinstall": "./scripts/patch-ts.sh",
  2. Add the following to scripts/patch-ts.sh (and remember to run chmod +x ./scripts/patch-ts.sh

    
    #!/bin/bash

FROM="var defaultMaximumTruncationLength = 160;" TO="var defaultMaximumTruncationLength = 1e6;"

sed -i -e "s/$FROM/$TO/g" "node_modules/typescript/lib/typescript.js"

echo "Annotation Truncation Length patched successfully"



3. Run `yarn install` or `npm install`
4. Reload Window
5. ???
6. Profit
BoscoDomingo commented 5 days ago

Long term solution by @extremegf

in vscode

1. Using Ctrl+P, Go to `node_modules/typescript/lib/tsserver.js`

2. Find line `var defaultMaximumTruncationLength = 160`

3. Change it to `1000` or value of your choosing.

4. Open Ctrl+Shift+P menu, select TypeScript: Select TypeScript Version...

5. Ensure it's set to Use Workspace Version

6. Full restart VSCode - reloading workspace is not enough.

7. Verify that ... abbreviations are gone from type hints.

Since TypeScript 5.6 this is now located in node_modules/typescript/lib/typescript.js.

There also seems to be a noTruncation variable, not sure if that was there prior to 5.6 (related to noErrorTruncation tsconfig option) but I'm going to explore it a bit further

Edit: yeah it was just the noErrorTruncation stuff. Just set your defaultMaximumTruncationLength to 5k and you'll be good 👍🏼