Skip to content

Add JSON Language Service features to the IDE.#25518

Closed
CyrusNajmabadi wants to merge 194 commits intodotnet:masterfrom
CyrusNajmabadi:jsonFeatures
Closed

Add JSON Language Service features to the IDE.#25518
CyrusNajmabadi wants to merge 194 commits intodotnet:masterfrom
CyrusNajmabadi:jsonFeatures

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi commented Mar 16, 2018

This is a followup to #24110 . That PR adds the actual json parser and corresponding tests. This PR adds support in the IDE for features such as classification and squiggles. It was broken out to make the PRs easier to review.

[jcouv]
Builds on top of common infrastructure for embedded language services (PR #25985)

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner March 16, 2018 05:53
@CyrusNajmabadi CyrusNajmabadi changed the title Add JSON Language Service Features to the IDE. Add JSON Language Service features to the IDE. Mar 16, 2018
@jcouv jcouv added the Area-IDE label Apr 1, 2018

public bool IsProbablyJson(SyntaxToken token, CancellationToken cancellationToken)
{
if (IsDefinitelyNotJson(token, _syntaxFacts))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is redundant. TryParseJson also checks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. removed.

SyntaxToken stringLiteral, SyntaxNode argumentNode,
CancellationToken cancellationToken)
{
var parameter = _semanticFacts.FindParameterForArgument(_semanticModel, argumentNode, cancellationToken);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like _semanticFacts is only used in this method. Consider passing in as a parameter.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer this approach. All the data that stays constant for the Document is held as fields of the class, and the only data that is passed in is the stuff that can actually vary from call to call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#bydesign

}


public bool IsProbablyJson(SyntaxToken token, CancellationToken cancellationToken)
Copy link
Copy Markdown
Member

@jcouv jcouv Apr 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method doesn't seem to be used.
My bad. I had FAR window scoped to current project.

Nit: extra empty line above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used in: AbstractJsonStringDetectorDiagnosticAnalyzer

There we check if it looks like it's probably json, and doesn't have any markers that indicate it's definitely json (i.e. it's not "JToken.Parse"). In that case, we offer to add the // lang=json comment to indicate that we should light-up language services here.


HasJsonLanguageComment(token, _syntaxFacts, out var strict);

var chars = _virtualCharService.TryConvertToVirtualChars(token);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_virtualCharService is only used here. I think it could be passed as parameter instead.
One of the two callers is an unused method. The other caller can easily pass that service through.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same reason as above. i would prefer the only things passed in to be the information that varies. The data tthat is fixed (i.e. the semantic model, services, etc.) i would like to all be kept together and only be provided once.

ISemanticFactsService semanticFacts,
IVirtualCharService virtualCharService)
{
// Do a quick non-allocating check first.
Copy link
Copy Markdown
Member

@jcouv jcouv Apr 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the type is trimmed down, would it be better to make it a struct and simply create a new struct whenever needed (without a cache)?
Never mind, we need the cached "types of interest"...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Thta's why i went with thsi pattern.

var name = GetNameOfInvokedExpression(invokedExpression);
if (_syntaxFacts.StringComparer.Equals(name, _methodNameOfInterest))
{
// Is a string argument to a method that looks like it could be a Regex method.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Json instead of Regex

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#resolved.

return false;
}

public JsonTree TryParseJson(SyntaxToken token, CancellationToken cancellationToken)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this method is nice. It brings all the pieces together. I like it :-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks :)

return JsonParser.TryParse(chars, strict);
}

private bool AnalyzeStringLiteral(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method name is odd. Maybe "ParameterNameIsJson"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#Resolved.

}
#endregion

#region JSON
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR should only have JSON changes, but has Regex changes too.

@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change can probably be reverted.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.ValidateJsonString;

namespace Microsoft.CodeAnalysis.CSharp.ValidateJsonString
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is for Json, but the file name says "Regex"

// diagnostic for when we detect a string that should have /*language=json*/ added to it.
public const string JsonDetectionDiagnosticId = "IDE0046";
// diagnostic for when we have a known json string and we detect something wrong with it.
public const string JsonPatternDiagnosticId = "IDE0047";
Copy link
Copy Markdown
Member

@jcouv jcouv Apr 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to get squiggles for bad Json in the IDE, with this error code. Do I need to turn some option on?

Update: I was able to see squiggles in string s = /*lang=json*/ "{a: 1, b: new()}"; under the open paren. But it's barely visible.
image

I was able to see the QuickInfo with the diagnostic, but it only appears if your cursor doesn't accidentally trigger any other QuickInfo. Is that by design?
json-quickinfo

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pdate: I was able to see squiggles in string s = /lang=json/ "{a: 1, b: new()}"; under the open paren. But it's barely visible.

What's the experience in the IDE elsewhere for this sort of error? I'm not sure how to necessarily make that better if we're only squiggling the open paren. That said, we could squiggle more, and thus make the squiggle more visible.

I was able to see the QuickInfo with the diagnostic, but it only appears if your cursor doesn't accidentally trigger any other QuickInfo. Is that by design?

Yeah, you can get the same QI behavior today in other areas of your code. However, things are very exacerbated with regex/json strings since you're always hovering over part of a string. I think i should probably suppress normal QI for these strings so you don't have the issue you've identified. Great catch!

public Task<BraceMatchingResult?> FindBracesAsync(Document document, int position, CancellationToken cancellationToken)
=> CommonJsonBraceMatcher.FindBracesAsync(document, position, cancellationToken);
}
}
Copy link
Copy Markdown
Member

@jcouv jcouv Apr 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In testing this, I noticed that VsVim must be implementing its own brace matching logic...
If I have a mismatched brace inside a string, the VsVim command for jumping to the other side (%) jumps to the wrong location. I'll let Jared know.
Update: Edit.GoToBrace (default binding: Ctrl+]) works better :-)

@jcouv
Copy link
Copy Markdown
Member

jcouv commented Apr 5, 2018

This PR currently has much content that will be reviewed in other PRs, and it is tedious to winnow the changes to review from the changelist.
I'll wait for the lower-level PR (parsing) to be merged before I finish this review (that'll remove a bunch of files). Could you also remove the regex changes and retarget the json feature branch? Thanks

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

I'll wait for the lower-level PR (parsing) to be merged before I finish this review (that'll remove a bunch of files).

Agreed!

Could you also remove the regex changes and retarget the json feature branch? Thanks

Of course. Sorry about that. I must have accidentally merged in the regex branch as that wasn't supposed to be in here.

@CyrusNajmabadi CyrusNajmabadi changed the base branch from master to features/embeddedJson April 6, 2018 03:21
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@jcouv I removed all the regex changes from this PR. I also rejiggered how IDE features work for embedded languages. Instead of requiring IDE features (like brace matching) to know about each embedded language, i've instead made it so that embedded langauges can register IDE features and they'll be picked up automatically.

This means we can add more embedded languages in hte future (like regex and beyond), without needing to go update all these end features.

@jcouv
Copy link
Copy Markdown
Member

jcouv commented Apr 6, 2018

Thanks. I'll look this weekend.
Just curious, would it name sense to automatically add closing braces and parens when typing in JSON string?

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

CyrusNajmabadi commented Apr 6, 2018

Just curious, would it name sense to automatically add closing braces and parens when typing in JSON string?

Yup. It most likely would. Not taht this gets a bit more challenging as typing really wants to be as synchronous as possible, whereas a lot of this embedded language stuff is async (as we have to look to see if you're actually instantiating a regex or parsing json and whatnot). That's why i didn't do it originally.

@CyrusNajmabadi CyrusNajmabadi changed the base branch from features/embeddedJson to master February 28, 2019 06:16
@jinujoseph
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi closing this PR as discussed previously.
We can reopen and work together when we will reconsider this

@jinujoseph jinujoseph closed this Jun 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee. Need Design Review The end user experience design needs to be reviewed and approved.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants