Skip to content
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

Add ConfigurationProvider API, ${workspaceRoot} -> ${workspaceFolder} #1801

Merged
merged 12 commits into from
Nov 3, 2017

Conversation

WardenGnaw
Copy link
Contributor

Adding ConfigurationProvider API

Changing ${workspaceRoot} to ${workspaceFolder}

tasks.json to version 2.0.0 and updating associated tests.

Copy link
Member

@DustinCampbell DustinCampbell left a comment

Choose a reason for hiding this comment

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

Could you check my comment about WorkspaceInformationResponse.MsBuild being null? This can happen for project.json.

* except the first in a workspace.
*/
private checkWorkspaceInformationMatchesWorkspaceFolder(folder: vscode.WorkspaceFolder, info: WorkspaceInformationResponse): boolean {
return info.MsBuild.SolutionPath === folder.uri.fsPath;
Copy link
Member

Choose a reason for hiding this comment

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

Note: It is entirely possible for MsBuild to be null.

Copy link
Member

Choose a reason for hiding this comment

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

Other than this, the change looks good to me. Note that this can be null when the project is a project.json file.

/**
* TODO: Remove function.
*
* Note: serverUtils.requestWorkspaceInformation only retrieves one project. Therefore, generator will be incorrect for all folders
Copy link
Member

Choose a reason for hiding this comment

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

serverUtils.requestWorkspaceInformation only retrieves one project.

This isn't true.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a way to make it retrieve all projects in the current workspace for VsCode?

Copy link
Member

Choose a reason for hiding this comment

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

It will retrieve all projects loaded by OmniSharp. Currently, OmniSharp can only target a single folder. However, that folder contains multiple .csproj projects or an .sln with multiple projects, it will return them. We're going to be doing some work in omnisharp-roslyn to make OmniSharp support multiple folders: OmniSharp/omnisharp-roslyn#909

@DustinCampbell
Copy link
Member

If this requires 1.18, we have to wait until the next VS Code is out before shipping, correct?

@gregg-miskelly
Copy link
Contributor

Correct.

@DustinCampbell
Copy link
Member

Do we want to get this in for 1.13 then? IIRC, the PR you just merged works around the issue that the debug.start command is being removed in 1.18. So, if we hold 1.13 that for this change, there'll be a window of time where things won't really work.

@DustinCampbell
Copy link
Member

Also, what API are we talking about? Debug configuration providers have been present for a little while.

@WardenGnaw
Copy link
Contributor Author

During my testing, the current stable version of VsCode (1.17.2) was not providing initial configurations with the DebugConfigurationProvider.

@DustinCampbell
Copy link
Member

During my testing, the current stable version of VsCode (1.17.2) was not providing initial configurations with the DebugConfigurationProvider.

Got it -- thanks! In that case, how do we want to coordinate this change? Should we hold it until after 1.13?

@gregg-miskelly
Copy link
Contributor

gregg-miskelly commented Oct 25, 2017

@WardenGnaw: is it possible to keep things working in 17.2 - it wouldn't have new functionality, but the old functionality would still be there?

If not, we will definitely need to wait till post 1.13.

@WardenGnaw
Copy link
Contributor Author

@gregg-miskelly Yep. We would only need to put back initialConfigurations in launch.json.

@gregg-miskelly
Copy link
Contributor

@WardenGnaw would that still retain the benefits in 1.18? (Will they ignore initialConfigurations if we have a provider)

@WardenGnaw
Copy link
Contributor Author

@gregg-miskelly No. We are using it as a JSON object literal, so it will not be ignored.

@WardenGnaw
Copy link
Contributor Author

@DustinCampbell @gregg-miskelly I lied. This feature should work for 1.17.2. I'll be reverting the package.json to 1.17.0.

I was testing the C/C++ extension at the same time as this one. They do some overwriting of the activation events which made me lose the "onDebug" event which is required for DebugConfigurationProvider.

@DustinCampbell
Copy link
Member

You shouldn't lie. 😄

@gregg-miskelly
Copy link
Contributor

            const generator = new AssetGenerator(info);

This will currently just check the workspace root for a launch.json/tasks.json. Do we need to check all the root folders instead?


Refers to: src/assets.ts:500 in b3b56af. [](commit_id = b3b56af, deletion_comment = False)

/**
* Returns a list of initial debug configurations based on contextual information, e.g. package.json or folder.
*/
provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, token?: vscode.CancellationToken): vscode.ProviderResult<vscode.DebugConfiguration[]> {
Copy link
Contributor

Choose a reason for hiding this comment

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

undefined [](start = 64, length = 9)

Can this really be undefined? If so, we don't seem to handle it.

Copy link
Contributor

Choose a reason for hiding this comment

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

@WardenGnaw did you see question?

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 I did see the question, VsCode had the function defined as that in their interface and I copied it over. So I added a check for folder but it got removed during other changes.

}

/**
* TODO: Remove function.
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO [](start = 7, length = 4)

Can we remove this now?

Copy link
Contributor Author

@WardenGnaw WardenGnaw Oct 26, 2017

Choose a reason for hiding this comment

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

Can I retrieve other workspace folder information with the change in #1806? Or this is still waiting on OmniSharp/omnisharp-roslyn#909.

Copy link
Contributor

Choose a reason for hiding this comment

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

@DustinCampbell should this work now?

Copy link
Member

Choose a reason for hiding this comment

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

You're waiting on OmniSharp/omnisharp-roslyn#909. OmniSharp is not being launched on multiple workspace folders. Instead, the user can now launch OmniSharp on targets within multiple workspace folders.

Copy link
Contributor

Choose a reason for hiding this comment

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

In that case I would suggest:

  • Add a link the bug
  • Instead of checking if the solution path is the same, seems like we should be checking if the folder is what we launched OmniSharp against.

Copy link
Member

@DustinCampbell DustinCampbell Oct 26, 2017

Choose a reason for hiding this comment

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

Yes, I hadn't spotted that we were checking the SolutionPath against the folder name. That's going to be wrong. Note that you can have an .sln file and OmniSharp can be launched directly on that file. In that case SolutionPath will point to the .sln.

Copy link
Contributor

@gregg-miskelly gregg-miskelly left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM, but I think I would like to take a second look

New tasks schema from 0.1.0 to 2.0.0
package.json's initialConfiguraitons have been deprecated. It uses
DebugConfigurationProvider instead.

C# extension uses generate assets initially to create launch.json and
tasks.json. However, if a user desides to dismiss the message and
generate via f5, the prompt will initiate the
DebugConfigurationProvider.
${workspaceRoot} is now ${workspaceFolder}

ConfigurationProvider activates on f5. This will also trigger generating
a tasks file.

tasks args are now 'build <path>', updating tests for these changes.
Copy link
Contributor

@gregg-miskelly gregg-miskelly left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM

{
serverFolder = path.dirname(solutionPathOrFolder);
}
return folder && folder.uri && (folder.uri.fsPath === serverFolder);
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 you want to check that solutionPathOrFolder is under folder.uir.fsPath rather than they exactly match. Otherwise if you open "c:\MyEnlistment" and your solution is in "c:\MyEnlistment\src" I believe your check will fail.

/**
* Returns a list of initial debug configurations based on contextual information, e.g. package.json or folder.
*/
provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, token?: vscode.CancellationToken): vscode.ProviderResult<vscode.DebugConfiguration[]> {
Copy link
Contributor

Choose a reason for hiding this comment

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

@WardenGnaw did you see question?

src/assets.ts Outdated
@@ -327,7 +325,7 @@ function getBuildTasks(tasksConfiguration: tasks.TaskConfiguration): tasks.TaskD

function findBuildTask(tasksDescriptions: tasks.TaskDescription[]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is VSCode's behavior if the user has an old style tasks.json? Should we be ignoring their tasks.json, replacing it, or is it really okay to add a new style task to an old style 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.

@gregg-miskelly The current behavior if a user has 0.1.0 in the version field of tasks.json is only an issue if they decide to use workspace folders.
image

Therefore, if we see an old tasks.json that is nonempty, we should be ignoring it. We could add a warning message saying to upgrade it if they wish to use workspace folders?

Checking if folder.uri.fsPath is a subfolder of GetSolutionPathOrFolder
to generate assets.
@@ -32,25 +32,21 @@ declare module "vscode-tasks" {
export interface BaseTaskConfiguration {

Choose a reason for hiding this comment

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

Why do we have a copy of these typings? In the 1.1.6 version of the vscode package I see that these types are already defined in vscode.d.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.

Not sure why we originally had a copy of this. @DustinCampbell may be able to answer that question. However, the current typings do not have the old Tasks schema, specifically isBuildCommand.

Copy link
Member

Choose a reason for hiding this comment

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

Back in the day, it wasn't included in vscode.d.ts.

fs.ensureDirSync(dotVscodeFolder);

// if the file does not exist, addTasksJson
const addTasksJson: boolean = !fs.existsSync(tasksJsonPath);

Choose a reason for hiding this comment

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

I'm preparing a PR to take advantage of the taskProvider API. We'll want to keep these two implementations in-sync. I'm also adding quite a bit of test infrastructure that we can use to ensure that they are in sync.

@WardenGnaw
Copy link
Contributor Author

@DustinCampbell, when you have the time. Can you review this PR again?

Copy link
Member

@DustinCampbell DustinCampbell left a comment

Choose a reason for hiding this comment

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

I have a few comments, and I'd like to be sure that we test the new feature extensively. However, I sign off on the change.

@@ -193,6 +193,7 @@
"vscode": "^1.17.0"
},
"activationEvents": [
"onDebug",
Copy link
Member

Choose a reason for hiding this comment

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

Does this mean that the C# extension will activate whenever the user starts debugging any non-CS file? If so, wouldn't that be a bad experience if the user installs the C# extension, tries to debug JS and the C# extension starts downloading OmniSharp and the debugger?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This activation event is required for DebugConfigurationProviders.

https://code.visualstudio.com/updates/v1_17#_debug-contributions-in-packagejson

Copy link
Member

Choose a reason for hiding this comment

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

Sure, but that's not what I asked. 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, I forgot to mention that I will still look into if the C# extension is activated in a node project. That was an FYI of why its there. :)

Copy link
Member

Choose a reason for hiding this comment

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

Thanks!

Copy link
Member

Choose a reason for hiding this comment

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

Clever! In that case, this seems like a reasonable approach.

Copy link
Member

Choose a reason for hiding this comment

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

@gregg-miskelly: Do you think we should do this for 1.13, or are you OK with doing it in 1.14, Same question for @TheRealPiotrP

Copy link
Contributor

Choose a reason for hiding this comment

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

@DustinCampbell do you mean the change all up or the switch to use the '*' activation event?

If change all up - @WardenGnaw how broken are we in the VS Code 1.18 (the one that is just about to come out in stable channel) without this? Are the things we are replacing just deprecated or are the broken?

If the '*' activation - I don't have a strong opinion. I am happy to wait for 1.14 on that part if you would like.

Copy link
Member

Choose a reason for hiding this comment

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

I meant using the '*' activation event. I'm OK with waiting for 1.14 for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Without the '*' activation event, we are not broken.

This was to fix the rare scenarios of people installing the C# extension, not opening a C# project for a while, then going to a non-C# project and then F5'ing would case the C# dependencies to start downloading.

src/assets.ts Outdated
export function createWebLaunchConfiguration(programPath: string, workingDirectory: string): string {
return `
{
"name": ".NET Core Launch (web)",
Copy link
Member

Choose a reason for hiding this comment

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

Any reason not to indent this like you did below to make it a bit more readable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops. Lost indentation when copying.

src/assets.ts Outdated
@@ -294,7 +292,7 @@ function findExecutableProjectJsonProjects(projects: protocol.DotNetProject[], c
return result;
}

function containsDotNetCoreProjects(workspaceInfo: protocol.WorkspaceInformationResponse) {
export function containsDotNetCoreProjects(workspaceInfo: protocol.WorkspaceInformationResponse) {
Copy link
Member

Choose a reason for hiding this comment

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

It feels like this helper should move someplace else if it needs to be accessed by more than just the assets generation. Perhaps src/omnisharp/protocol.ts? There's already other helpers like this there: https://github.com/OmniSharp/omnisharp-vscode/blob/master/src/omnisharp/protocol.ts#L589-L592.

src/common.ts Outdated
* @param subfolder subfolder to check if it is part of the folder parameter
* @param folder folder to check aganist
*/
export function isSubfolderOf(subfolder: string, folder:string): boolean {
Copy link
Member

Choose a reason for hiding this comment

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

Does this work if the paths differ by case? Does it matter?

Copy link
Member

Choose a reason for hiding this comment

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

Nit: space after folder:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DustinCampbell Case sensitivity matters for Linux OS. Should I make it insensitive for Windows and Mac?

Copy link
Member

Choose a reason for hiding this comment

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

Not necessarily. If both values are expected to have the correct casing, it shouldn't matter. However, if they come from different sources, it might be a problem.

const tasksJsonPath: string = path.join(dotVscodeFolder, 'tasks.json');

// Make sure .vscode folder exists, addTasksJsonIfNecessary will fail to create tasks.json if the folder does not exist.
fs.ensureDirSync(dotVscodeFolder);
Copy link
Member

Choose a reason for hiding this comment

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

I'm seeing a lot of synchronous file I/O mixed with async code. Any concerns with 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.

I'm not too experienced with async programming patterns. I used the synchronous version of ensureDir and exist to make sure the .vscode folder exists and to make sure the .vscode/tasks.json does not exist before calling addTasksJsonIfNecessary. Is there a better way to do this?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think there's any concern for these small checks. I just wanted to make note of it.

Copy link
Member

Choose a reason for hiding this comment

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

FWIW, NodeJS async isn't really challenging. Someday, maybe you can spend some time digging into it since the platform really hangs on asynchronous patterns. It's not necessary now.

}
else {
// Error to write default C# configurations.
throw new Error("Does not contain dotnet core projects.");
Copy link
Member

Choose a reason for hiding this comment

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

If this message gets surfaced to the user, that should be ".NET Core", not "dotnet core"

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 does not get surfaced to the user since its caught by the .catch(), but I will still change it.

src/common.ts Outdated
* @param folder folder to check aganist
*/
export function isSubfolderOf(subfolder: string, folder: string): boolean {
if (os.platform() !== 'win32')
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you mean to do something here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Assuming your idea was to try and solve the case sensitivity problem, here is my thought - I don't think we should try to solve it. From what I can tell, I think the paths we are dealing with are all from the VS Code search APIs using the same roots they are providing to us, so it seems like it would be very surprising if we saw the same path but with different case. Solving the casing problem in java script is likely a hard problem. For one because on both OSX and Linux its possible to have either case sensitivity or insensitivity (though OSX is generally insensitive and Linux is sensitive). For another because I don't know how closely the java script casing tables are actually going to match what the OS uses.

My suggestion: Just add a note to the header that the two paths must have consistent casing.

Copy link
Member

Choose a reason for hiding this comment

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

My suggestion: Just add a note to the header that the two paths must have consistent casing.

yup. That's what I was thinking too.

@@ -71,6 +71,28 @@ export class DebugInstaller {
let manifestString = fs.readFileSync(manifestPath, 'utf8');
let manifestObject = JSON.parse(manifestString);

manifestObject.activationEvents = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Per Dustin's comment, this can wait for the next PR, but this needs to go to a different spot - I think we need to rewrite activationEvents at the very start of our activation handler if it is still set to [ "*" ] to make sure that we will not continuously try to download things in the case that we don't succeed in downloading the debugger.

Copy link
Contributor

@gregg-miskelly gregg-miskelly left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM assuming we back out the last commit.

Removing empty if and assuming paths have consistent casing.
@WardenGnaw WardenGnaw merged commit 03b89c4 into dotnet:master Nov 3, 2017
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.

5 participants