vscode-powershell icon indicating copy to clipboard operation
vscode-powershell copied to clipboard

Add support for workspace profiles

Open daviwil opened this issue 8 years ago • 31 comments

It'd be nice if we provided a way for the user to configure a startup script which gets run when VS Code opens their project folder. This would allow them to configure their session for the project they're developing without having to add anything extra to their profile. This would also allow registration of project-specific editor commands using the $psEditor API.

daviwil avatar May 18 '16 15:05 daviwil

After thinking about this a bit, it seems like the most obvious way to approach this is to define the concept of a "workspace profile" that gets loaded in addition to the VS Code host profiles. When the user loads a folder in VS Code, we'll look for a file called .profile.ps1 (or better suggestion) in the root of the workspace path and then load that along with the other host profiles.

This will be useful when a project has certain modules it needs to load when the user loads up the project. This could also be useful to other editors so I won't be making it editor-specific (not placing the profile in the .vscode subfolder).

Thoughts? @rkeithhill

daviwil avatar Jul 19 '17 07:07 daviwil

I really like that idea. Would make development of modules and such much easier especially if I need to override installed modules with development versions.

PowerSchill avatar Jul 19 '17 13:07 PowerSchill

I like the idea. Do you want to load that file by a "conventional" name like .profile.ps1 or indirectly via a setting that defaults to ${workspaceRoot}/.profile.ps1. Not sure it's worth the extra level of indirection and there is some value in always being able to identify this file. And the extra level of indirection is something that could be added later if we find it is needed.

rkeithhill avatar Jul 19 '17 14:07 rkeithhill

If it is going to be editor agnostic, it would make sense to continue the pattern to have a generic Workspace profile and a Host/Editor specific profile that can be used.

WorkspaceAllHosts    : {WorkspaceRoot}\Workspace.profile.ps1
WorkspaceCurrentHost : {WorkspaceRoot}\Workspace.VSCode_profile.ps1

WorkspaceAllHosts would work well to cover the module loading scenarios since most of them shouldn't care about the Host to run.

WorkspaceCurrentHost would cover the $psEditor commands that might be specific to an Editor that you wouldn't want to load up in another one.

dragonwolf83 avatar Jul 19 '17 16:07 dragonwolf83

Like the idea, but not sure about using a generic file name like profile.ps1. I can imagine someone loading a project with a file named that and inadvertently running some code they didn't intend to. A safer way would be to include this in the .vscode folder, but i know you plan to leave this open for other editors. What if we had a project-level setting in there that would contain the path to the project profile script? That way you could choose to store it in the workspace root or any where else, and name it whatever you like.

mattmcnabb avatar Jul 19 '17 16:07 mattmcnabb

@dragonwolf83 Considering that this setting would only be in VSCode I don't think you would need multiple values. For Example in Sublime Text you would need something to be stored in their project file.

PowerSchill avatar Jul 19 '17 16:07 PowerSchill

I can see @mattmcnabb point. My PowerShell profile is a project so if I were using that workspace it would run every time. Let me offer a suggestion of the default profile to be workspace_profile.ps1. I think that would greatly reduce the conflict possibilities.

By default the workspace profile would be {WorkspaceRoot}\workspace_profile.ps1 but could be overriden in the project settings.

PowerSchill avatar Jul 19 '17 16:07 PowerSchill

Maybe this frickin' Linux stuff is starting to rub off on me but I'm strangely attracted to .profile.ps1. :-) That said ... considering all other PowerShell profiles do not start with a ., I'd go something like what @PowerSchill suggests. Is the term workspace editor agnostic?

rkeithhill avatar Jul 19 '17 17:07 rkeithhill

@rkeithhill The workspace term is not used in all editors as many will use project but I think the definition of the term is clear enough that it can be safely used and understood.

@PowerSchill I don't see why it wouldn't work in Sublime Text if there is an Integrated Terminal with PowerShell Editor Services. The $PSEditor extension reads the Project/Workspace settings from the Editor and automatically loads $profile.WorkspaceCurrentHost and $profile.WorkspaceAllHosts if they exist.

As long as $PSEditor is told when a project, folder, workspace or whatever is switched, it should be able to open a new runspace and load the correct $profile(s).

For example, I can see this being very useful in Visual Studio where I have scripts that automate Visual Studio in COM. I can open my project and have it run the PowerShell extension to run those commands or load a module that makes it easier to run those commands.

@mattmcnabb if you referring to my post on name profile.ps1. The PowerShell highlighting sucks on GitHub, the name I had was Workspace.profile.ps1. I tend to like dot notations rather than underscores as a personal preference.

@jaykul is any of this useful in what you did with Jupyter? I think your feedback would be good on this.

dragonwolf83 avatar Jul 19 '17 18:07 dragonwolf83

I'm just saying that if there's a chance that a user will update the extension and then open a workspace that contains a file matching whatever the naming convention may be, then there is a risk and this should be avoided. Any code that is automtically run at load should be explicitly agreed to by the user. If the path to this file is set by a setting in the .vscode/settings.json and the setting is off by default, then the user should be protected against inadvertently launching a script.

mattmcnabb avatar Jul 19 '17 18:07 mattmcnabb

@dragonwolf83

I tend to like dot notations rather than underscores as a personal preference.

Given that the existing host-specific profiles already use _ having a default of workspace_profile.ps1 makes the most sense to me. However, if this is controlled by an editor setting then you would be free to use .. :-)

rkeithhill avatar Jul 19 '17 18:07 rkeithhill

Definitely love this idea.

For security reasons would it be possible to have a prompt once per workspace? Similar to how VSCode handles workspace terminal customizations.

As for the file name, I'd like to throw ProjectName.profile.ps1 into the running. Similar to the InvokeBuild build script naming scheme.

SeeminglyScience avatar Jul 19 '17 22:07 SeeminglyScience

The main reason why I suggested .profile.ps1 is because the naming doesn't stand out a whole lot in the project's root folder (i.e. it's not ugly looking). For some reason I'm aesthetically opposed to workspace_profile.ps1 as the standard name, just seems too long and clunky. If we go with something more specific than .profile.ps1, I'd probably go with @SeeminglyScience's recommendation of FolderName.profile.ps1 since the file name would at least match that of the project (and be more obvious in the process).

Regarding whether we'd have a separate "all editors" profile, I think I'd prefer to keep things simple and not require a project to have multiple files for all the possible editors that developers in the project might want to use. I think it'd be better if the profile script could modify it's behavior based on the editor it gets loaded in. The goal of PS Editor Services is to minimize the need for editor-specific behavior, so I think we've failed if it's absolutely necessary to have separate profiles per editor.

I'm also inclined to not allow this to be configured (at least at first). PowerShell doesn't let you customize it's profile paths :) The route I'd opt for is to have a standard naming convention so that you never have to look at the project's settings (across multiple editors...) to figure out what the workspace profile script is. I'd prefer to establish a standard name based on user feedback and then stick with that.

daviwil avatar Jul 20 '17 04:07 daviwil

Forgot to mention the security aspect: I can definitely show an initial prompt to ask the user whether they want to load the workspace profile for this project.

daviwil avatar Jul 20 '17 04:07 daviwil

I would prefer the .profile.ps1 because on the *nix platforms it becomes just another hidden file right? That's a behavior I wish we could emulate on Windows.

Just my 2 cents worth... 😊

gwojan avatar Jul 20 '17 10:07 gwojan

@gwojan that's actually part of my problem with that name.

Do we really want this file to be hidden? I feel like it would be one of the first files you want to look at when opening someone else's project for the first time. Especially if it is registering editor commands.

SeeminglyScience avatar Jul 20 '17 11:07 SeeminglyScience

To be honest as long as its a preference I don't really care as much since I can set it to what I want. But for the general public it is a bigger deal. I do kind of like the .profile but I also am very familiar with Linux/OSX systems so its normal for me. Considering that most users, I am guessing, are Windows users and are not familiar with it. Using other examples; InvokeBuild uses *.build.ps1 files and Pester uses *.test.ps1; I tend to think that maybe we should use *.profile.ps1.

With that said I am comfortable with any of the options stated.

PowerSchill avatar Jul 20 '17 12:07 PowerSchill

Thanks for all the feedback! I think at first I'll go with ProjectName.profile.ps1 and then see what kind of feedback we get then potentially add a setting if people want more flexibilty.

daviwil avatar Jul 20 '17 19:07 daviwil

Sounds good. And if we need to add the setting, we can use "${workspaceRootFolderName}.profile.ps1.

rkeithhill avatar Jul 20 '17 21:07 rkeithhill

Talking this one out with @tylerl0706, this may make sense to discuss at the PowerShell Core level as well (i.e. should this be loaded only in editors?). /cc @SteveL-MSFT

joeyaiello avatar Dec 06 '17 18:12 joeyaiello

Not sure if this issue needs reviving or not, but I would really appreciate this feature.

I'm thinking primarily on folders that correspond with a repository. With this feature, all contributors would have the same initialization/settings/environment when they start working on the repo.

I don't really care about the filename nor the location of the file, but the .vscode folder looks like an obvious choice when implemented for VSC only.

For VSC an enable/disable flag in the workspace settings would be a requirement for me.

lucdekens avatar Sep 17 '18 06:09 lucdekens

Just wanted to chime in with what might be considered a novel workaround — since the PowerShell Integrated Console for a workspace always starts up with the workspace root as the working directory, you can add code to your Microsoft.VSCode_profile.ps1 that attempts to resolve to a file relative to the workspace root.

For example, you could do something like $WorkspaceProfiles = Resolve-Path .\*.profile.ps1 and then source the results if any exist.

NReilingh avatar Sep 03 '19 23:09 NReilingh

It looks like we just need to prepend const startEditorServices in process.ts with . <path-to-workspace-profile>;. Is my assessment correct?

In my opinion, adding an extension setting pointing to the profile is much preferred than a "magic" solution, as this feature would then be implicitly documented with the rest of the extension settings and subsequently much more discoverable.

chriskuech avatar Dec 13 '19 04:12 chriskuech

It looks like we just need to prepend const startEditorServices in process.ts with . <path-to-workspace-profile>;. Is my assessment correct?

Not exactly, the idea is that it would be a profile per workspace similar to VSCode's settings.json but for setting up PowerShell context. Adding something at the workspace level that gets invoked automatically is potentially dangerous. For this feature to be feasible I think one of these would need to be true:

  1. Disabled by default, cannot be overridden at the workspace level. This one isn't my preference because one of the main things I think this would be useful for is setting up PowerShell context for contributors of a public project. There's a lot of things you can do to set up intellisense like set up type accelerators, import non-public module functions into global, etc. This option limits the utility of that to folks who already have that enabled. It's also an either or type of thing, where ideally you'd want to enable this for some workspaces and disable for others.

  2. Enabled with prompt by default. Ideally when a workspace is entered, we'd check for a workspace profile and prompt the user to determine if they'd like to run it. Preferably with Yes/No/Always/Never options.

In my opinion, adding an extension setting pointing to the profile is much preferred than a "magic" solution, as this feature would then be implicitly documented with the rest of the extension settings and subsequently much more discoverable.

I don't see any problem with that. There could be a workspace overridable setting that specifies a profile path, though I would prefer a sensible default value as the "magic" option.

SeeminglyScience avatar Dec 13 '19 13:12 SeeminglyScience

What if we break up the implementation into the two steps below to start unblocking and gaining traction?

  1. Read a specific profilePath from settings.json and load it into the session, such that no auto-execution of code is enabled by default--only enabled by explicitly updating settings.json.
  2. Automatically determine the profilePath from the environment and prompt the user asking whether to run the profile.

chriskuech avatar Dec 13 '19 18:12 chriskuech

  1. Read a specific profilePath from settings.json and load it into the session, such that no auto-execution of code is enabled by default--only enabled by explicitly updating settings.json.

I'm not really sure what problem that's solving to be honest. That makes them too individualized for what I'm picturing (imo). Also you could set this up currently in your $profile.CurrentUserCurrentHost pretty easy:

# $psEditor.Workspace.Path currently gives a malformed path in the
# preview version of the extension, but should be fixed next release.
$workspaceProfile = Join-Path $psEditor.Workspace.Path -ChildPath MyProfileName.ps1
if (Test-Path -LiteralPath $workspaceProfile) {
    . $workspaceProfile
}

If a feature is introduced to vscode-powershell that extends that functionality, I would personally prefer that it be more generalized.

Automatically determine the profilePath from the environment and prompt the user asking whether to run the profile.

That's more or less what I mean by option 2 in my post above. The setting to override it is the easy part, the harder (but probably still not too hard) part is setting up the prompt (particularly with the Always/Never options).

SeeminglyScience avatar Dec 13 '19 18:12 SeeminglyScience

Right now there is no way to make linting work with custom modules, as you can in other language extensions. All I want is to make linting work automatically for repo contributors--defining a profile path in settings.json that gets checked in seems like a perfect candidate for this, as well as add the internal hook for adding more complex scenarios in the future.

My point is that these steps aren't mutually exclusive and breaking down the problem into smaller pieces will increase the likelihood of gaining traction towards implementing all the pieces.

If someone from the vscode-powershell team can confirm that this would be implemented by dot-sourcing the correct path in process.ts (and adding the necessary settings), then I can PR the change.

chriskuech avatar Dec 13 '19 19:12 chriskuech

Right now there is no way to make linting work with custom modules, as you can in other language extensions. All I want is to make linting work automatically for repo contributors--defining a profile path in settings.json that gets checked in seems like a perfect candidate for this

Would that be a workspace level setting or a user level setting? If the former, then that would still require the safe guards be in place. If the latter, then it's not automatic and (imo) doesn't provide significant value over having the above sample in your profile.

My point is that these steps aren't mutually exclusive and breaking down the problem into smaller pieces will increase the likelihood of gaining traction towards implementing all the pieces.

Yes and no. We have historically had a lot of half implemented features that never really went anywhere. I absolutely agree that this can be a fantastic feature, but I think there are some key parts to this feature that can't be skipped.

If someone from the vscode-powershell team can confirm that this would be implemented by dot-sourcing the correct path in process.ts (and adding the necessary settings), then I can PR the change.

Unfortunately that won't work. When the start up script is ran it creates a new runspace, this is how we are able to implement our own PSHost while still using powershell.exe/pwsh directly. That would potentially work for environment variables, but just about everything else would be lost.

The actual invocation would need to be done from PowerShellEditorServices (the language server vscode-powershell uses).

Here is where the profiles are executed. Though you may need to alter ProfilePathInfo since it is currently hard coded to the same four options as $profile is typically.

You can also implement the prompt from there potentially, but I can't remember if the LSP will be busy while the console is initializing. If it's not busy, you can send a showMessageRequest from the language server to determine if the profile should be invoked. If it is busy then it may be better to do as a separate request sent from vscode-powershell to PowerShellEditorServices after initialization.

As long as there is a prompt, and a sensible default file name (preferably {WorkspaceName}.profile.ps1), I think that's good enough for an initial implementation. I think the Never/Always options can come later.

SeeminglyScience avatar Dec 13 '19 22:12 SeeminglyScience

I found myself needing this type of functionality. Also providing a nudge, almost, exactly 1 year from @SydneyhSmith nudge :).

ctmcisco avatar Dec 14 '20 17:12 ctmcisco

I'm not an expert at this by any stretch of the imagination, but would a half-measure be a way to specify the HostProfileId when starting up PSES? Honestly, I don't even know what that parameter does specifically (I tried to read the code but quickly got lost), but it sounds like it might change the Profile Host Id from Microsoft.VSCode to something custom for the workspace.

While that doesn't quite get 100% there, it's one setup step to put the appropriate .ps1 file in your PowerShell directory where it would get picked up. This also avoids the security concerns about running arbitrary code on first load of a workspace with the option set.

Again, I don't know if that would work and I don't know nearly enough about the extension or PSES. I don't know if the dots I'm seeing connect into a picture or a mess, thus why I'm just leaving this here for more experienced minds to ponder.

egerlach avatar Jan 07 '23 18:01 egerlach