Skip to content

(GH-1336) Add syntax aware folding provider #1355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 2, 2018

Conversation

glennsarti
Copy link
Contributor

@glennsarti glennsarti commented Jun 9, 2018

PR Summary

Fixes #1336

Adds a syntax aware folding provider, hidden behind a feature flag.

PR Checklist

Note: Tick the boxes below that apply to this pull request by putting an x between the square brackets.
Please mark anything not applicable to this PR NA.

Outstanding items

  • Outstanding style questions about .forEach
  • Question about moving getCoreNodeModule into util.js
  • Question about whether to convert FP style to imperative for the powerShellGrammarPath function

Required features

  • Functions (Fixed in { } support)
  • Regions (#region and # region)
  • Here strings
  • Comment Blocks (# .... \n# ....>)
  • Comment based help (<# .... #>)
  • Make folding provider optional (via config)

Additional features added

  • Hashtable folding (From { } support)
  • Array folding (From ( ) support)

PR Review requirements

  • PR has a meaningful title
  • Summarized changes
  • This PR is ready to merge and is not work in progress
    • If the PR is work in progress, please add the prefix WIP: to the beginning of the title and remove the prefix when the PR is ready
  • MEGA BONUS POINTS - It has tests!!
  • Add logging in the provider/feature
  • Converting comments into JSDoc format
  • Convert to Literal regex

@glennsarti
Copy link
Contributor Author

This is purely just to show the work I've done so far. It is far from complete (and breaks about 10,000 typescript linting rules :-) )

My current thinking is;

  • Use the client side textmate grammar file to tokenize the source
  • Once I have that, I can make decisions as to where code begins
  • Once I know where code begins and ends I can craft the required FoldingRange objects

Note that the syntax folding supersedes any "default" folding regions e.g. # region or line break/indentation style.

@glennsarti
Copy link
Contributor Author

I have brackets ( { } and ( ) ) working

brackets

It's hard to see but...you'll notice the default folding is there until the extension is loaded, which "magically" removes the folding for the # region section.

@glennsarti glennsarti force-pushed the add-syntax-folding branch from a339bc6 to 63650a0 Compare June 10, 2018 13:57
@rkeithhill
Copy link
Contributor

rkeithhill commented Jun 10, 2018

Use the client side textmate grammar file to tokenize the source
Once I have that, I can make decisions as to where code begins

It sounds like you are redoing work the parser has already done. For example, getting here string folding region info amounts to this:

$tok = $err = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile("$pwd\examples\DebugTest.ps1", [ref]$tok, [ref]$err)
$ast.FindAll({param($ast) ($ast -is [System.Management.Automation.Language.StringConstantExpressionAst]) -and (($ast.StringConstantType -eq [System.Management.Automation.Language.StringConstantType]::DoubleQuotedHereString) -or ($ast.StringConstantType -eq [System.Management.Automation.Language.StringConstantType]::SingleQuotedHereString))}, $true) | 
    Foreach-Object Extent |
    Select-Object StartLineNumber, EndLineNumber

Which, for my test file outputs:

StartLineNumber EndLineNumber
--------------- -------------
              3             9
             34            36

We have the ability from the TS extension source to make a request over to the PS Editor Services such that it can execute PowerShell code for us including queries on the AST. This is how the code analysis diagnostics are reported. This is how help completion works. This is how "Find PS modules from Gallery" works. The one area that the AST doesn't help with is comments which includes region support - since that is implemented as "special" comment. Anyway, I had envisioned the folding support would take advantage of the AST for most everything else.

If you need help with the infrastructure to callback to PSES as well as the PSES C# infrastructure to process the request - let me know.

@glennsarti
Copy link
Contributor Author

glennsarti commented Jun 11, 2018

Hi @rkeithhill . Thanks for taking the time to look at my WIP. I did consider using the Language Server to surface this information but I decided against it for the following reasons:

  1. If the language server crashes, you lose folding. This is a "breaking change" behaviour of the extension, where folding still works (Indentation based) if the lang. server is unavailable

  2. VS Code is the only editor I can see that allows syntax aware folding (Atom and Sublime do not. Didn't check VIM). So this feature is specific to VSCode so it seems to belong in the vscode extension, not the generic Editor Services.

  3. You can get the region comments by using the tokens generated by the ::ParseFile method ($tok). But at this point you're replicating things in the lang. server you could do client side.

  4. Reduce complexity. By adding another "thing" to the lang. server. including all the work to add that "thing", and all the plumbing that goes with it, is the increased complexity (and to some degree latency) worth it?. In my opinion, no. We can do the same work client side (using the grammar file), with almost exact accuracy as the native PowerShell parser, without the complexity overhead.

Note - By complexity, I'm more referring to the system as a whole, as opposed to complex for a developer to write/understand.

  1. (This point is debatable) I feel it makes more sense for the token decisions to come from the textmate grammar than the lang. server.

Folding should follow the visual cues of the editor. The visual cues come from the colourisation and syntax highlighting, which come the textmate grammar. These cues do not come from the lang. server. But ... you could easily argue that the lang. server knows more about the file and should be considered the authority.

Of course there are downsides to going client side:

  1. The powershell grammar tokens I'm looking for would become hard-coded. So if there were changes to the scope names in the grammar file, the folding provider would fail to see them. This means the client side method is fragile to grammar scope name changes.

Now, is this possible? of course it's possible we'll have changes. Is this probable? For the tokens I'm looking for, not likely. Is this testable? Yes, tests could be written to make sure the folding provider continues to function as expected.

@rkeithhill
Copy link
Contributor

rkeithhill commented Jun 11, 2018

If the language server crashes, you lose folding.

And intellisense, code analysis, code formatting, code lens, etc. When the language server crashes, it's a bad day. I don't think that's a good reason to not utilize the language server for some of this.

you could easily argue that the lang. server knows more about the file and should be considered the authority.

Yup. In addition, the tm grammar we've been using has been a steady source of issues/complaints. I'm not particularly confident in its ability to support PowerShell adequately. This bug was fixed recently (the = after ParameterSetName throws it off):

image

For the longest time, Where-Object, Sort-Object, Select-Object wouldn't get colorized correctly. That was recently fixed but we still get a pretty steady stream of tm grammar issues - see https://github.com/powershell/editorSyntax/issues

I'm probably more than a little jaded about the tm grammar. :-) Heck, if I had my druthers we'd use an API like what is being proposed here: microsoft/vscode#585 Which is essentially how Visual Studio does syntax colorization. It asks the language service to provide colorization info.

By adding another "thing" to the lang. server. including all the work to add that "thing", and all the plumbing that goes with it, is the increased complexity (and to some degree latency) worth it?

Depends. If you can provide all the desired folding regions without all the corner cases bugs we seem to so frequently run into with the tm grammar, then no, it's not worth using the AST via the lang server. OTOH I'd have more confidence in the information we get from AST i.e. I wouldn't worry about corner-cases. But I'm willing to be proven wrong. It could be my low opinion of the tm grammar is unwarranted. :-)

BTW, lest I come off too negative, I really do appreciate the contribution!! Proper here string folding is something folks have been asking for, for a long time now. Just want to make sure we have a healthy debate about the best approach and wanted to make you're aware that using the AST is a fairly easy option.

@glennsarti
Copy link
Contributor Author

Just want to make sure we have a healthy debate about the best approach

Agreed! FWIW I'm one of the authors of the Puppet extension and I have the same debates where to stick features client vs Lang. Server. Always trade-offs

There is also a middle ground, which is to implement client side until the server side code is complete, and then just switch over. Could even hide it behind a vscode setting to make it an opt-in feature. Adding a command to the language server is not trivial, to me anyway. I am not usually a C# developer so the ramp-up time is not small. The plumbing to call the server from the client I can handle ok (copy-n-paste to a degree). If it's decided to go down that route, not client side, I probably won't be able to assist.

Regarding the TM issues... I personally haven't had them, however I too am just a sample size of one :-)

If you can provide all the desired folding regions without all the corner cases bugs we seem to so frequently run into

For the tokens we're interested in in this PR, I don't feel it's too bad, but that's just a gut feel, no data to back it up.


So to wrap up.

  • The Language Server is probably the final resting place for the folding logic to be determined, and right now I will not be able to assist with that.

  • But I, as a community member, can provide an interim solution using the grammar file for tokenisation, until the more correct solution (lang server) is implemented. The interim solution can be opt-in which should help with supporting the interim feature.

  • Switching over from the client side to server side logic will be transparent to the vscode users.

@rkeithhill
Copy link
Contributor

Sounds good. If I can carve off some time to work on the PSES impl, what info does the client need besides start/end line pairs?

@glennsarti
Copy link
Contributor Author

Needs enough information to populate - https://code.visualstudio.com/docs/extensionAPI/vscode-api#FoldingRange

  • Start
  • End
  • Type of region - Comment, Imports (N/A to us) and Region.

@rkeithhill
Copy link
Contributor

Interesting. So what FoldingRangeKind do you use for functions and here strings?

@glennsarti
Copy link
Contributor Author

I was going to use 'Region' for everything except comments

@rkeithhill
Copy link
Contributor

I wonder if we should provide feedback to the VSCode team that we'd like to have a few more "kinds" e.g. function/method, verbatim/here string, or maybe just "Other" as a catchall.

@glennsarti
Copy link
Contributor Author

Sure. I hadn't thought that far ahead.

@TylerLeonhardt
Copy link
Member

Awesome discussion guys :) I agree that PSES should be, in the end, where the folds come from. Another benefit I don't think was mentioned is that other editors could implement syntax aware folding and those editors can get it for free/minimal effort :)

It would also be good to have all the using statements in PowerShell folded as an imports type but this is much lower pri IMO.

@rjmholt
Copy link
Contributor

rjmholt commented Jun 11, 2018

Hmmmm I definitely see the motivation to make folding all happen client side. Especially since folding should be simple.

But the truth is that trying to do it that way we will inevitably come across things that a TM Grammar is simply not powerful enough to recognise - PowerShell is woefully grammatically complex. The parser is the final arbiter of what text is what token, and if we handle ASTs properly (i.e. cache them, etc), it should all be very cheap too.

@rkeithhill as an aside: I too really want that hook-in highlighting functionality - would be very useful for things like dynamic keyword support and function highlighting.

@glennsarti glennsarti force-pushed the add-syntax-folding branch from 38ea9ea to cd19f84 Compare June 13, 2018 14:01
@glennsarti
Copy link
Contributor Author

After happens when the following is in the user settings

    "powershell.developer.featureFlags": [
        "syntax-folding"
    ],
Before After
image image

@glennsarti glennsarti changed the title WIP: (GH-1336) Add syntax aware folding provider (GH-1336) Add syntax aware folding provider Jun 13, 2018
@glennsarti
Copy link
Contributor Author

@rkeithhill and @rjmholt PR is done. Ready for review.

@TylerLeonhardt
Copy link
Member

@omniomi is the big contributor to EditorSyntax which is where the syntax highlighting comes from.

Nick, if you have some time, can you take a look at this PR and give your thoughts on this since this change depends on EditorSyntax?

@omniomi
Copy link
Contributor

omniomi commented Jun 13, 2018

From a quick look over none of the scopes used for folding in this PR are likely to change as they were all corrected in an older PR. That said, @glennsarti I'll add begin and end scopes to here-strings which I just noticed are missing.

@tylerl0706 I think we're at the point we should create a dependency document for EditorSyntax to track the potential fallout from changes. Ie, where it's used, any specific scope dependencies, as well as processes for having dependents update to newer revisions.

Copy link
Member

@TylerLeonhardt TylerLeonhardt left a comment

Choose a reason for hiding this comment

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

I've got a few comments but it all looks really good!

document: vscode.TextDocument) {
this.start = start;
this.end = end;
if (startLine === null) {
Copy link
Member

Choose a reason for hiding this comment

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

You could use a ternary operator here:

this.startline = startLine ? startLine : document.positionAt(start.startIndex).line;

Copy link
Contributor

Choose a reason for hiding this comment

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

I was going to suggest ||, but both suggestions are wrong since startLine can be 0.

Needs to be:

this.startLine = startLine !== null ? startLine : document.positionAt(start.startIndex).line;

And if there's a worry about the possibility of undefined being a possible value of startLine, == will work for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No longer an issue.

} else {
this.startline = startLine;
}
if (endLine === null) {
Copy link
Member

Choose a reason for hiding this comment

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

same ternary op.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No longer an issue.

document: vscode.TextDocument,
context: vscode.FoldingContext,
token: vscode.CancellationToken,
): Promise<vscode.FoldingRange[]> {
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: I noticed some of your functions look like this:

public foo(
    doc: bar
    context: baz
) : Boo {
// ...
}

and some look like:

public foo(doc: bar
           context: baz) : Boo {
// ...
}

Is there a reason for the different indenting? Can we align those if not? (I personally prefer the first style 😄)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's my ruby-isms coming through :-). Will reformat to first one :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Somewhat fixed. I've reformatted the code I wrote, haven't done the code I copy-pasta'd from other sources.

}
});

return result.reverse();
Copy link
Member

Choose a reason for hiding this comment

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

if you need to return the reversed result, maybe use result.unshift instead of result.push?

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

}

// Given a zero based offset, return the line number in the document
private lineAtOffest(offset: number,
Copy link
Member

Choose a reason for hiding this comment

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

looks like a typo: Offest -> Offset

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

}
});

// If we exist the token array and we're still processing comment lines, then the
Copy link
Member

Choose a reason for hiding this comment

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

did you mean "If we exit"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

document: vscode.TextDocument): string {
const startPos = document.positionAt(offset);
// We don't know how long the line is so just return a really long one.
const endPos = startPos.translate(0, 1000);
Copy link
Member

Choose a reason for hiding this comment

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

you can get the whole line with:

document.lineAt(document.positionAt(offset)).rangeIncludingLineBreak
//or
document.lineAt(document.positionAt(offset)).range // for no LineBreak

from that can we accurately get the start and end position?

Copy link
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
Contributor

@rjmholt rjmholt left a comment

Choose a reason for hiding this comment

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

This generally looks really great!

One thing we should consider is breaking up some of the denser sections of FP-style code into foreach loops, etc., just to align it more with the rest of the codebase and to make it easier to maintain for the maintainers.

Thanks so much for your contribution @glennsarti 😃!

@@ -5,7 +5,7 @@
"publisher": "ms-vscode",
"description": "Develop PowerShell scripts in Visual Studio Code!",
"engines": {
"vscode": "^1.22.0"
"vscode": "^1.23.0"
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the version increment required for this PR? I don't think we have a particular policy, but dependency version changes are important enough that it would be worth considering having that as its own PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. The Folding API only exists in 1.23.0+

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The previous changes didn't separate PRs for it.
790e6e2

5ad413c

#748

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, I'm convinced 😄

@tylerl0706 Maybe we should consider this a policy for the future, especially with all the feature work going into VSCode — I know .NET Core's latest update was surprisingly tricky for PowerShell.

Copy link
Member

Choose a reason for hiding this comment

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

I guess we could. We haven't gotten burned by it yet AFAIK but it doesn't hurt. Next time :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Next time was last time :-P

const tm = getCoreNodeModule("vscode-textmate");
// Returns a node module installed with VSCode, or null if it fails.
// https://github.com/Microsoft/vscode/issues/46281
function getCoreNodeModule(moduleName: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

A general function like this might fit better in utils.ts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably, but this is a bit edge-case-y and is only consumed in this file. Would you still prefer I move it to utils?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rjmholt I've moved that function as a private method within the feature (to help with loading). So it's no longer a general function. Given this, it's it still something I should change for this PR?

function getCoreNodeModule(moduleName: string) {
try {
return require(`${vscode.env.appRoot}/node_modules.asar/${moduleName}`);
// tslint:disable-next-line:no-empty
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than disabling tslint, we should probably log the inability to retrieve the module.

// Need to reproduce the IToken interface from vscode-textmate due to
// the odd way it has to be required
// https://github.com/Microsoft/vscode-textmate/blob/46af9487e1c8fa78aa1f2e2/release/main.d.ts#L161-L165
export interface IToken {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think ideally we should put exported definitions at the top of the file (in the same way as public members of an object).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops, that interface is internal only. Removed the export.

}

// The different types of matched textmate tokens.
// Mirrors the enum at https://code.visualstudio.com/docs/extensionAPI/vscode-api#FoldingRangeKind
Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally we should be using JSDoc-style comments for classes and methods. This project is a bit lacking in documentation and documenting comments, but this is what I imagine documentation looking like (not saying it's stellar - I wrote it - but the first example I could think of).

I think TypeScript has some integration with JSDoc comments that gives richer IDE integration as well. Here is a page that goes into more detail on JSDoc comments in TypeScript.

@tylerl0706 and @rkeithhill might have differing opinions on this btw 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd rather be consistently wrong, than wrong in inconsistent ways :-). I'll convert the comments over.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm open to using JSDoc comments on functions - where we actually document said functions. :-)

try {
const psGrammars =
vscode.extensions.all
.filter((x) => x.packageJSON && x.packageJSON.contributes && x.packageJSON.contributes.grammars)
Copy link
Contributor

Choose a reason for hiding this comment

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

The x, a and b in this method are probably a bit too terse, especially since they are not annotated with a type. Maybe give them expressive names and ideally type annotations.

It might also be worth taking the filter, reduce and map methods and turning them into more a verbose, imperative form, mainly because it's the dominant style elsewhere in the project. (Want to be clear that I'm philosophically in favour of a functional style, but want to unpack the functionality here a bit)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed the variable names. However I didn't convert to imperative, but instead, added code comments as breadcrumbs for future-us. Would that be enough?

this.foldingProvider);
}

// tslint:disable-next-line:no-empty
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like these tslint pragmas might be necessary, but I would like to get rid of them if possible. I see there are recommendations to return undefined or void, but I'm not sold on that either. Thoughts?

Copy link
Contributor Author

@glennsarti glennsarti Jun 14, 2018

Choose a reason for hiding this comment

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

returning void is probably fine.

Nope, tslint didn't like that. Just did return undefined; instead.

Fixed


}

export class FoldingFeature implements IFeature {
Copy link
Contributor

Choose a reason for hiding this comment

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

This class should probably be defined at the top of the file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was copying the src/features/DocumentFormatter style.

"punctuation.section.group.begin.powershell",
"punctuation.section.group.end.powershell",
MatchType.Region, document)
.forEach((x) => { matchedTokens.push(x); });
Copy link
Contributor

Choose a reason for hiding this comment

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

The xs used here and below should be renamed more descriptively.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

document: vscode.TextDocument) {
this.start = start;
this.end = end;
if (startLine === null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I was going to suggest ||, but both suggestions are wrong since startLine can be 0.

Needs to be:

this.startLine = startLine !== null ? startLine : document.positionAt(start.startIndex).line;

And if there's a worry about the possibility of undefined being a possible value of startLine, == will work for that.

@glennsarti
Copy link
Contributor Author

glennsarti commented Jun 14, 2018

Yeah @omniomi , one thing that's missing from this PR is tests. In theory I should be able to write some simple integration tests (e.g. Given text content X, it should return Y folding regions).

For better or worse, as this is behind a feature flag, I don't need as good test coverage, yet!. This should give me enough time to figure out how to download a grammar test fixture, and write appropriate tests.

@glennsarti glennsarti force-pushed the add-syntax-folding branch from 7311340 to 4793314 Compare June 14, 2018 03:42
Previously the Powershell extension used the default VSCode indentation based
folding regions.  This commit adds the skeleton for a syntax aware, client-side
folding provider as per the API introduced in VSCode 1.23.0

* The client side detection uses the PowerShell Textmate grammar file and the
  vscode-text node module to parse the text file into tokens which will be
  matched in later commits.

* However due to the way vscode imports the vscode-textmate module we can't
  simply just import it, instead we need to use file based require statements
  microsoft/vscode#46281

* This also means it's difficult to use any typings exposed in that module.  As
  we only need one interface, this is replicated verbatim in the file, but not
  exported

* Logging is added to help diagnose potential issues
This commit adds detection of text regions bounded by braces { } and parentheses
( ).  This provides syntax aware folding for functions, arrays and hash tables.
This commit adds detection of text regions composed of single and double
quoted here strings;  @' '@ and @" "@.
This commit adds syntax aware folding for comment regions

* Contiguous blocks of line comments `# ....`

* Block comments `<# ... #>`

* Region bound comments `# region ...  # endregion`
Previously the syntax folding was available for all users.  However it was able
to be configured or turned off.  This commit adds a new `codeFolding` settings
section, with the syntax folding feature enabled by default.
Previously there were no tests to verify the folding provider.  Due to the
provider depending on 3rd party libraries (vscode-textmate and PowerShell
grammar file) these tests will provide a degree of detection if breaking changes
occur.
Previously tslint was raising errors in Travis CI saying that the excluded test
fixtures directory was not included in the project.  This was by design however
it appears to be a known bug palantir/tslint#3793.

This commit removes the exclude for test files from linting and adds a tslint
directive in the default index.ts file.  A tslint directive is used instead of
solving the issue because this is the default testing file for VS Code extesions
and shouldn't really be modified unless absolutely necessary.  In this instance
it was safer for a tslint directive.
@glennsarti glennsarti force-pushed the add-syntax-folding branch from 302c1c0 to 5156173 Compare June 29, 2018 02:27
@glennsarti
Copy link
Contributor Author

@tylerl0706 @rjmholt Addressed all comments. CI is green...

@@ -0,0 +1,588 @@
import * as path from "path";
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the story on source file copyright notices? Every other .ts file seems to have this copyright notice on the first line:

/*---------------------------------------------------------
 * Copyright (C) Microsoft Corporation. All rights reserved.
 *--------------------------------------------------------*/

Even those contributed by community members.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

❓ Contributing guide/s makes no mention. I've already signed the CLA.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I, as a non-Microsoft employee, shouldn't add that, as I don't represent them.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't mention this as a blocker but an inquiry as to what the policy is. Back in January I went through this code-base and cleaned up source to pass tslint as part of effort to achieve some form of engineering compliance (#1086). I'm curious if that "compliance" has anything to say about copyright notices.

Copy link
Collaborator

@SeeminglyScience SeeminglyScience Jun 29, 2018

Choose a reason for hiding this comment

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

I, as a non-Microsoft employee, shouldn't add that, as I don't represent them.

FWIW the copyright is their's either way, and ultimately the one representing Microsoft is whomever publishes the release.

I view it more as "informing of a copyright" rather than "declaring copyright".

That said, I'm not sure what the point of it is - at least in an MIT licensed project. Maybe @tylerl0706 or @rjmholt could check if there is a policy on this? If there isn't, my vote would be to remove it or at least omit it going forward.

(This is just a general note, definitely shouldn't hold up the PR)

Copy link
Member

Choose a reason for hiding this comment

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

added the headers

Copy link
Contributor

Choose a reason for hiding this comment

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

Btw, I looked at our contriibution guide and was about to add a note but wasn't sure of where to add it or how to phrase it. I also notice that PowerShell doesn't seem to have a note about it either, only in their PR checklist.

Copy link
Member

Choose a reason for hiding this comment

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

We could add it to the PR checklist :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Offtopic - @SeeminglyScience - Ceeding copyright to Microsoft is fine. It was more the "All rights reserved". IANAL, but I didn't feel I was in position to represent to Microsoft to say what rights other people had. Again this all moot (Heh, I used legal term!) due to me signing the CLA.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tylerl0706 @rjmholt Raised #1394 to add automation to enforce header rule.

Copy link
Contributor

@rkeithhill rkeithhill left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@rjmholt rjmholt left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks so much for your contribution @glennsarti!

@TylerLeonhardt
Copy link
Member

Merging this in tomorrow morning :) unless people have further comments

@glennsarti
Copy link
Contributor Author

Merge it now

@TylerLeonhardt TylerLeonhardt merged commit ef63eea into PowerShell:master Jul 2, 2018
@TylerLeonhardt
Copy link
Member

It's "Squash" not "Smash" psh.... Hulk, please git good.

This is merged!! 😄

@glennsarti
Copy link
Contributor Author

No Squash

rjmholt pushed a commit that referenced this pull request Jul 11, 2018
* (GH-1336) Add syntax aware folding provider

Previously the Powershell extension used the default VSCode indentation based
folding regions.  This commit adds the skeleton for a syntax aware, client-side
folding provider as per the API introduced in VSCode 1.23.0

* The client side detection uses the PowerShell Textmate grammar file and the
  vscode-text node module to parse the text file into tokens which will be
  matched in later commits.

* However due to the way vscode imports the vscode-textmate module we can't
  simply just import it, instead we need to use file based require statements
  microsoft/vscode#46281

* This also means it's difficult to use any typings exposed in that module.  As
  we only need one interface, this is replicated verbatim in the file, but not
  exported

* Logging is added to help diagnose potential issues

* (GH-1336) Add syntax folding for braces and parentheses

This commit adds detection of text regions bounded by braces { } and parentheses
( ).  This provides syntax aware folding for functions, arrays and hash tables.

* (GH-1336) Add syntax folding for here strings

This commit adds detection of text regions composed of single and double
quoted here strings;  @' '@ and @" "@.

* (GH-1336) Add syntax folding for comments

This commit adds syntax aware folding for comment regions

* Contiguous blocks of line comments `# ....`

* Block comments `<# ... #>`

* Region bound comments `# region ...  # endregion`

* (GH-1336) Add integration tests for the Folding Provider

Previously there were no tests to verify the folding provider.  Due to the
provider depending on 3rd party libraries (vscode-textmate and PowerShell
grammar file) these tests will provide a degree of detection if breaking changes
occur.

* (maint) Modify tslint configuration for test files

Previously tslint was raising errors in Travis CI saying that the excluded test
fixtures directory was not included in the project.  This was by design however
it appears to be a known bug palantir/tslint#3793.

This commit removes the exclude for test files from linting and adds a tslint
directive in the default index.ts file.  A tslint directive is used instead of
solving the issue because this is the default testing file for VS Code extesions
and shouldn't really be modified unless absolutely necessary.  In this instance
it was safer for a tslint directive.

* (GH-1336) Add Code Folding settings and enable by default

Previously the syntax folding was available for all users.  However it was able
to be configured or turned off.  This commit adds a new `codeFolding` settings
section, with the syntax folding feature enabled by default.

* add copyright headers
glennsarti added a commit to glennsarti/PowerShellEditorServices that referenced this pull request Nov 12, 2018
This commit adds the the code to return folding ranges when the server receives
a FoldingRangeRequest.  This commit;

* Uses a similar method to that implemented in the VS Code extension [1]
* Uses the PowerShell tokeniser instead of the AST.  This is due to the AST
  ignoring comment sections.  Without the comment parsing folding for #region
  etc. will not work
* Translates the tests in VS Code [1] into equivalent C# tests

[1] PowerShell/vscode-powershell#1355
glennsarti added a commit to glennsarti/PowerShellEditorServices that referenced this pull request Nov 13, 2018
This commit adds the the code to return folding ranges when the server receives
a FoldingRangeRequest.  This commit;

* Uses a similar method to that implemented in the VS Code extension [1]
* Uses the PowerShell tokeniser instead of the AST.  This is due to the AST
  ignoring comment sections.  Without the comment parsing folding for #region
  etc. will not work
* Translates the tests in VS Code [1] into equivalent C# tests

[1] PowerShell/vscode-powershell#1355
glennsarti added a commit to glennsarti/PowerShellEditorServices that referenced this pull request Nov 14, 2018
This commit adds the the code to return folding ranges when the server receives
a FoldingRangeRequest.  This commit;

* Uses a similar method to that implemented in the VS Code extension [1]
* Uses the PowerShell tokeniser instead of the AST.  This is due to the AST
  ignoring comment sections.  Without the comment parsing folding for #region
  etc. will not work
* Translates the tests in VS Code [1] into equivalent C# tests

[1] PowerShell/vscode-powershell#1355
glennsarti added a commit to glennsarti/PowerShellEditorServices that referenced this pull request Nov 14, 2018
This commit adds the the code to return folding ranges when the server receives
a FoldingRangeRequest.  This commit;

* Uses a similar method to that implemented in the VS Code extension [1]
* Uses the PowerShell tokeniser instead of the AST.  This is due to the AST
  ignoring comment sections.  Without the comment parsing folding for #region
  etc. will not work
* Translates the tests in VS Code [1] into equivalent C# tests

[1] PowerShell/vscode-powershell#1355
glennsarti added a commit to glennsarti/PowerShellEditorServices that referenced this pull request Nov 16, 2018
This commit adds the the code to return folding ranges when the server receives
a FoldingRangeRequest.  This commit;

* Uses a similar method to that implemented in the VS Code extension [1]
* Uses the PowerShell tokeniser instead of the AST.  This is due to the AST
  ignoring comment sections.  Without the comment parsing folding for #region
  etc. will not work
* Translates the tests in VS Code [1] into equivalent C# tests

[1] PowerShell/vscode-powershell#1355
glennsarti added a commit to glennsarti/PowerShellEditorServices that referenced this pull request Nov 16, 2018
This commit adds the the code to return folding ranges when the server receives
a FoldingRangeRequest.  This commit;

* Uses a similar method to that implemented in the VS Code extension [1]
* Uses the PowerShell tokeniser instead of the AST.  This is due to the AST
  ignoring comment sections.  Without the comment parsing folding for #region
  etc. will not work
* Translates the tests in VS Code [1] into equivalent C# tests

[1] PowerShell/vscode-powershell#1355
glennsarti added a commit to glennsarti/PowerShellEditorServices that referenced this pull request Nov 22, 2018
This commit adds the the code to return folding ranges when the server receives
a FoldingRangeRequest.  This commit;

* Uses a similar method to that implemented in the VS Code extension [1]
* Uses the PowerShell tokeniser instead of the AST.  This is due to the AST
  ignoring comment sections.  Without the comment parsing folding for #region
  etc. will not work
* Translates the tests in VS Code [1] into equivalent C# tests

[1] PowerShell/vscode-powershell#1355
glennsarti added a commit to glennsarti/PowerShellEditorServices that referenced this pull request Nov 22, 2018
This commit adds the the code to return folding ranges when the server receives
a FoldingRangeRequest.  This commit;

* Uses a similar method to that implemented in the VS Code extension [1]
* Uses the PowerShell tokeniser instead of the AST.  This is due to the AST
  ignoring comment sections.  Without the comment parsing folding for #region
  etc. will not work
* Translates the tests in VS Code [1] into equivalent C# tests

[1] PowerShell/vscode-powershell#1355
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Collapsible/expandable Functions, Regions, Comment blocks, and Comment based help blocks
7 participants