From 53b8b3a7f565fb94a7cb983ffdf832d8168a42aa Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Thu, 16 May 2019 22:46:55 -0300 Subject: [PATCH 01/22] initial commit --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 105 +++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 1-Draft/RFCNNNN-Implicit-Line-Continuance.md diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md new file mode 100644 index 00000000..d5bdef41 --- /dev/null +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -0,0 +1,105 @@ +--- +RFC: RFCnnnn +Author: Kirk Munro +Status: Draft +SupercededBy: N/A +Version: 1.0 +Area: Parser/Tokenizer +Comments Due: June 16, 2019 +Plan to implement: Yes +--- + +# Support implicit line continuance when using named parameters or splatting in commands + +Nobody likes having to use the backtick to wrap commands in PowerShell, yet many users still use it to get the style they prefer in their scripts. + +For example, PowerShell has long supported explicit line continuance when you end a pipelined command line with a pipe symbol, like this: + +```PowerShell +Get-Process -Id $PID | + Stop-Process +``` + +Even though that is available, when you have a pipeline with many stages (commands) in it, the style is not as desirable as it could be if you could place the pipeline on the beginning of the line instead, like this: + +```PowerShell +Get-Process -Id $PID + | Stop-Process +``` + +Historically that syntax would not be possible unless you ended each line before the last line in the pipeline with a backtick. That shouldn't be necessary though, and PowerShell should be smart enough to recognize implicit line continuance when pipelines are placed at the beginning of the line. This was discussed in detail in [Issue #3020](https://github.com/PowerShell/PowerShell/issues/3020), and [PR #8938](https://github.com/PowerShell/PowerShell/pull/8938) that was recently merged added this support to PowerShell for version 7. + +While that is helpful, there is another potential improvement where PowerShell could support implicit line continuance: when using named parameters or splatting in commands, and that's what this RFC is about. + +For example, consider this example of a New-ADUser command invocation: + +```PowerShell +New-ADUser -Name 'Jack Robinson' -GivenName 'Jack' -Surname 'Robinson' -SamAccountName 'J.Robinson' -UserPrincipalName 'J.Robinson@enterprise.com' -Path 'OU=Users,DC=enterprise,DC=com' -AccountPassword (Read-Host -AsSecureString 'Input Password') -Enabled $true +``` + +By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage it in a script. To wrap this command across multiple lines, users can either use backticks, or they can use splatting. The former is a nuisance which should really only be used in situations when PowerShell cannot implicitly intuit how lines are wrapped. The latter is helpful, but users lose the benefits of tab completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's generally onerous. Even though Visual Studio Code has an extension that makes splatting easier, as can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense for future updates unless you work from the command first and then add to your splatted collection, and that's just in Visual Studio Code. Other editors may or may not support that functionality, and users working in a standalone terminal won't have that available to them either. + +Instead, why not allow users to do this by supporting implicit line continuance when using named parameters: + +```PowerShell +New-ADUser + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + -UserPrincipalName 'J.Robinson@enterprise.com' + -Path 'OU=Users,DC=enterprise,DC=com' + -AccountPassword (Read-Host -AsSecureString 'Input Password') + -Enabled $true +``` + +Further, if they have some parameters they want to splat in (because splatting is not just about shortening lines -- it's very useful for users to apply common parameters/values to multiple commands), let them do this as well: + +```PowerShell +$commonParams = @{ + Path = 'OU=Users,DC=enterprise,DC=com' + Enabled = $true +} +New-ADUser + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + -UserPrincipalName 'J.Robinson@enterprise.com' + -AccountPassword (Read-Host -AsSecureString 'Input Password') + @commonParams +``` + +## Motivation + + As a script/module author, + I can wrap long commands across multiple lines at any named parameter or splatted collection, + so that my scripts are easier to maintain while I still get the benefits of Intellisense and tab completion. + +## Specification + +Note: This RFC is already implemented and submitted as [PR #9614](https://github.com/PowerShell/PowerShell/pull/9614). + +Since this RFC includes some breaking changes (see below), it will be initially implemented with the `PSImplicitLineContinuanceForNamedParameters` experimental feature flag. If the PowerShell Team and the community agree that the risk of this breaking change is low enough, and the workaround is sufficient for those low frequency use cases where it does become an issue, I would much prefer not using an experimental feature flag at all. + +For the implementation, this RFC builds on the work done in [PR #8938](https://github.com/PowerShell/PowerShell/pull/8938), evolving the logic used in the tokenizer that supports implicit line continuance for lines starting with a pipe such that it can be used to check for implicit line continuance for named parameters and splatted collections as well. To keep performance optimal, the parser logic that identifies command parameters where the implicit line continuance checks will be invoked will recognize if a pipe is found on a subsequent line as well, to ensure the lookahead logic is only invoked once per line in commands/pipelines. + +## Alternate Proposals and Considerations + +While implicit line continuance for splatted collections is not a breaking change (PowerShell syntax does not support `@variableName` at the start of a command), implicit line continuance for named parameters is a breaking change, because PowerShell syntax currently supports commands that start with dash. + +For example, consider this script: + +```PowerShell +function -dash { + 'run' +} + +-dash +``` + +In practice, I believe this to be a very low risk breaking change, because it is unlikely that (m)any users have defined functions or aliases that start with a dash, and in researching commands on Windows and Linux I was not able to find any commands with names that start with dash. However, in the event that someone is using such a command, they can still invoke it even if this breaking change is applied, by using the call operator as follows: + +```PowerShell +& -dash +``` From b1880c943d25bb6a969b495561eb4d40dfc1486f Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Fri, 17 May 2019 13:10:09 -0300 Subject: [PATCH 02/22] added new breaking change findings --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 49 ++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index d5bdef41..4ada4cf3 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -86,7 +86,7 @@ For the implementation, this RFC builds on the work done in [PR #8938](https://g ## Alternate Proposals and Considerations -While implicit line continuance for splatted collections is not a breaking change (PowerShell syntax does not support `@variableName` at the start of a command), implicit line continuance for named parameters is a breaking change, because PowerShell syntax currently supports commands that start with dash. +While implicit line continuance for splatted collections is not a breaking change (PowerShell syntax does not support `@variableName` at the start of a command), implicit line continuance for named parameters is a breaking change in some scenarios, because PowerShell syntax currently supports commands that start with dash, and PowerShell supports unary operators whose name starts with a single dash. For example, consider this script: @@ -95,11 +95,54 @@ function -dash { 'run' } +Get-Process -Id $PID -dash ``` -In practice, I believe this to be a very low risk breaking change, because it is unlikely that (m)any users have defined functions or aliases that start with a dash, and in researching commands on Windows and Linux I was not able to find any commands with names that start with dash. However, in the event that someone is using such a command, they can still invoke it even if this breaking change is applied, by using the call operator as follows: +In PowerShell 6.x and earlier, two commands will be executed: `Get-Process`, and `-dash`. With this PR in place and the experimental feature enabled, only one command would be executed: `Get-Process`. The reason is that the parser would identify `-dash` as being intended as a parameter on the command on the previous line. That's how the parser needs to work to make this implicit line continuance functional. + +Similarly, consider this script: ```PowerShell -& -dash +Get-Process -Id $PID +-split 'a b c d' ``` + +Similar to the previous example, in PowerShell 6.x and earlier, one command and one statement will be executed: `Get-Process`, and the unary `-split` statement. With this PR in place and the experimental feature enabled, only one command would be executed: `Get-Process`, because again, the parser would identify `-split` as being intended as a parameter on the command on the previous line. The same applies to the `-join` unary operator as well. It does not apply to the `--` prefix arithmetic operator because the parser knows parameter names cannot start with a dash. + +To fix this, users can do one of the following: + +1. For either example, insert a blank line between `Get-Process` and the next command that starts with dash, as shown here: + + ```PowerShell + function -dash { + 'run' + } + + Get-Process -Id $PID + + -dash # Runs the -dash command because implicit line continuance stops looking when it encounters a blank line + + Get-Process -Id $PID + + -split 'a b c d' # splits the string 'a b c d' into an array with four items + ``` + +1. In the example with a command that starts with a dash, invoke the command using the call operator, as shown here: + + ```PowerShell + function -dash { + 'run' + } + + Get-Process -Id $PID + & -dash # Runs the `-dash` command because implicit line continuance sees the call operator and recognizes that the line does not continue further + ``` + + Unfortunately this workaround does not work for the -split or -join unary operators, because you cannot invoke statement that starts with a unary operator with the call operator (the call operator is only for invoking commands). + +In practice, I believe that there are not many commands out there that start with a dash. While researching this, I couldn't find a single command on Windows or Linux that starts with a dash, so that's not a very risky scenario. However, since the `-split` and `-join` unary operators exist in PowerShell, there is a good likelihood that those may be used on a line following a command, and that is where this breaking change would have the most potential impact. While I don't feel that risk is enough to reject this proposal entirely, because it adds significant value to script authors, it is worth considering what the best approach would be. + +Special casing the named unary operators could work (among the thousands of commands on my system, none of them have split or join parameters, but some may exist somewhere), but that would mean future unary operators be special cased as well, so that approach isn't desirable because it risks future breaking changes. + +If the risk is deemed to be too high because of the risk with named unary operators, at a bare minimum I feel this feature offers enough significant value to the community that it should not be rejected, but instead offered as an optional feature so that users wanting the benefit can opt-into the functionality, and mark it as enabled for their scripts/modules. I also suspect the majority of scripters would want it turned on and would then simply write their scripts accordingly. It's really too bad though that unary operators with string names use the same single first character as parameter names because they get in the way here. In hindsight, named operators should probably have been prefixed with something other than a single dash to differentiate them from named parameters (something to consider if PowerShell ever comes out with a version with significant breaking changes plus conversion scripts). From 95051f0d3370de444bff434f42610d5be0b2e21f Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Fri, 17 May 2019 22:36:56 -0300 Subject: [PATCH 03/22] add alternatives and stop-parsing sigil support --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 39 +++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index 4ada4cf3..5549bafd 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -37,7 +37,7 @@ For example, consider this example of a New-ADUser command invocation: New-ADUser -Name 'Jack Robinson' -GivenName 'Jack' -Surname 'Robinson' -SamAccountName 'J.Robinson' -UserPrincipalName 'J.Robinson@enterprise.com' -Path 'OU=Users,DC=enterprise,DC=com' -AccountPassword (Read-Host -AsSecureString 'Input Password') -Enabled $true ``` -By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage it in a script. To wrap this command across multiple lines, users can either use backticks, or they can use splatting. The former is a nuisance which should really only be used in situations when PowerShell cannot implicitly intuit how lines are wrapped. The latter is helpful, but users lose the benefits of tab completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's generally onerous. Even though Visual Studio Code has an extension that makes splatting easier, as can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense for future updates unless you work from the command first and then add to your splatted collection, and that's just in Visual Studio Code. Other editors may or may not support that functionality, and users working in a standalone terminal won't have that available to them either. +By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage. To wrap this command across multiple lines, users can either use backticks, or they can use splatting. The former is a nuisance which should really only be used in situations when PowerShell cannot implicitly intuit how lines are wrapped. The latter is helpful, but users lose the benefits of tab completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's generally onerous. Even though Visual Studio Code has an extension that makes splatting easier, as can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense for future updates unless you work from the command first and then add to your splatted collection, and that's just in Visual Studio Code. Other editors may or may not support that functionality, and users working in a standalone terminal won't have that available to them either. Instead, why not allow users to do this by supporting implicit line continuance when using named parameters: @@ -70,6 +70,15 @@ New-ADUser @commonParams ``` +And lastly, if users have a bunch of arguments they want to pass after the stop parsing sigil (`--%`), let them do this also (thanks @Jaykul for the suggestion): + +```PowerShell +&"./plink.exe" + --% $Hostname -l $Username -pw $Password $Command +``` + +For the last one, `--%` stops the parsing of that command, so no further implicit line continuance may be used because that would require the parser which the scripter opted out of using for that command. + ## Motivation As a script/module author, @@ -146,3 +155,31 @@ In practice, I believe that there are not many commands out there that start wit Special casing the named unary operators could work (among the thousands of commands on my system, none of them have split or join parameters, but some may exist somewhere), but that would mean future unary operators be special cased as well, so that approach isn't desirable because it risks future breaking changes. If the risk is deemed to be too high because of the risk with named unary operators, at a bare minimum I feel this feature offers enough significant value to the community that it should not be rejected, but instead offered as an optional feature so that users wanting the benefit can opt-into the functionality, and mark it as enabled for their scripts/modules. I also suspect the majority of scripters would want it turned on and would then simply write their scripts accordingly. It's really too bad though that unary operators with string names use the same single first character as parameter names because they get in the way here. In hindsight, named operators should probably have been prefixed with something other than a single dash to differentiate them from named parameters (something to consider if PowerShell ever comes out with a version with significant breaking changes plus conversion scripts). + +### Some Non-Breaking Alternatives + +1. Require users to opt-in on any command where they want this wrapping by ending the first line (and only the first line) with a sigil. + + This suggestion was proposed by @jaykul. We could add a token at the end of a command and from that point on, treat subsequent lines as part of the same command if they begin with named parameters, splatted collections, or the stop-parsing sigil (`--%`). For example, this could be a multi-line command that follows these rules: + + ```PowerShell + New-ADUser @ + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + -UserPrincipalName 'J.Robinson@enterprise.com' + -Path 'OU=Users,DC=enterprise,DC=com' + -AccountPassword (Read-Host -AsSecureString 'Input Password') + -Enabled $true + ``` + + Pros: The @ symbol is familiar since it is used for splatting. + Cons: Users lose the benefit of not having to use any characters for line continuance. + +1. Add support for optional features to PowerShell, and make this feature optional, rather than experimental. + + The experimental feature is designed to be a temporary holding place until features are fully developed. There are advantages to having optional features as well, which users can opt into if they want the benefit. Ideally such functionality would have support for enabling optional features in both scripts and modules, so that the features could be used by script/module authors without impacting the experience of individual consumers of those scripts/modules. This alone (support for optional features) warrants another RFC, but assuming it is there and assuming such features can be turned on for scripts (via `#requires`?) and/or modules (via the manifest), scripters who want this capability could have it automatically turned on for new scripts/modules without risk to existing scripts/modules because they wouldn't have that feature enabled, thus preventing a breaking change. Anyone who wants this for existing scripts/modules could manually enable it and take on the responsibility of making their code work appropriately. + + Pros: Allows the feature to be used without any breaking changes, and without extra continuance characters. + Cons: Requires optional feature work in PowerShell (an RFC that I'd be happy to write). From ed40b38d9a47014e4b8aa88fe53807241265aff6 Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Fri, 17 May 2019 22:41:02 -0300 Subject: [PATCH 04/22] incorporated some additional feedback --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index 5549bafd..cde6a184 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -174,7 +174,7 @@ If the risk is deemed to be too high because of the risk with named unary operat -Enabled $true ``` - Pros: The @ symbol is familiar since it is used for splatting. + Pros: The @ symbol is familiar since it is used for splatting. Also, PSReadline could recognize when you're opting in to use this at the command prompt, only running the command if you hit enter twice (although this wouldn't be used nearly as often at the prompt -- it's really for scripts). Cons: Users lose the benefit of not having to use any characters for line continuance. 1. Add support for optional features to PowerShell, and make this feature optional, rather than experimental. From aef259ba2d3149e55e88ffb6cb052b1b099be48c Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Mon, 20 May 2019 11:39:48 -0300 Subject: [PATCH 05/22] added missing copyright notice --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 40 ++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index cde6a184..6d14df0b 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -177,9 +177,49 @@ If the risk is deemed to be too high because of the risk with named unary operat Pros: The @ symbol is familiar since it is used for splatting. Also, PSReadline could recognize when you're opting in to use this at the command prompt, only running the command if you hit enter twice (although this wouldn't be used nearly as often at the prompt -- it's really for scripts). Cons: Users lose the benefit of not having to use any characters for line continuance. + Here's another alternative sigil to do the same thing that is a bit more literal: + + ```PowerShell + New-ADUser ... + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + -UserPrincipalName 'J.Robinson@enterprise.com' + -Path 'OU=Users,DC=enterprise,DC=com' + -AccountPassword (Read-Host -AsSecureString 'Input Password') + -Enabled $true + ``` + + Pros: ... is literal and familiar. The same PSReadline benefits listed for the previous example apply. + Cons: The same cons listed in the previous example apply. + 1. Add support for optional features to PowerShell, and make this feature optional, rather than experimental. The experimental feature is designed to be a temporary holding place until features are fully developed. There are advantages to having optional features as well, which users can opt into if they want the benefit. Ideally such functionality would have support for enabling optional features in both scripts and modules, so that the features could be used by script/module authors without impacting the experience of individual consumers of those scripts/modules. This alone (support for optional features) warrants another RFC, but assuming it is there and assuming such features can be turned on for scripts (via `#requires`?) and/or modules (via the manifest), scripters who want this capability could have it automatically turned on for new scripts/modules without risk to existing scripts/modules because they wouldn't have that feature enabled, thus preventing a breaking change. Anyone who wants this for existing scripts/modules could manually enable it and take on the responsibility of making their code work appropriately. Pros: Allows the feature to be used without any breaking changes, and without extra continuance characters. Cons: Requires optional feature work in PowerShell (an RFC that I'd be happy to write). + +1. Add argument enclosure support to PowerShell. + + One reader of this RFC who expressed their dislike for this functionality was pointing out that they don't like the fact that there is no terminator to the wrapped command parameters, so PowerShell needs to determine when the command ends based on lookahead. If preferable, new syntax could be added to allow for argument enclosures so that there is a defined terminator. For example, consider this syntax: + + ```PowerShell + New-ADUser -{ + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + -UserPrincipalName 'J.Robinson@enterprise.com' + -Path 'OU=Users,DC=enterprise,DC=com' + -AccountPassword (Read-Host -AsSecureString 'Input Password') + -Enabled $true + } + ``` + + What's interesting about this syntax is that these don't need to be just (named) parameter enclosures. They can be defined as argument enclosures, allowing scripters to put whatever they want on whichever lines they want, wrapping where it makes sense for them to do so, while using named parameters, positional parameters, or arguments (for external commands that don't have parameters). + + Pros: Allows the feature to be used without any breaking changes (script blocks do not support negate or subtraction operators, so this new enclosure could be added without risk). Allows the scripter to wrap how they see fit, while still getting Intellisense and tab completion. Parameters and arguments are entered the same way they would be if they were all placed on one line (e.g. unlike splatting, parameter names are entered with dashes, no equals signs are required, etc.). + Cons: Requires a little extra syntax to make it work properly. + From d8c5ea0689565cf9775e079603ee48ff46ce9725 Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Mon, 20 May 2019 11:39:48 -0300 Subject: [PATCH 06/22] added more alternatives --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 40 ++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index cde6a184..6d14df0b 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -177,9 +177,49 @@ If the risk is deemed to be too high because of the risk with named unary operat Pros: The @ symbol is familiar since it is used for splatting. Also, PSReadline could recognize when you're opting in to use this at the command prompt, only running the command if you hit enter twice (although this wouldn't be used nearly as often at the prompt -- it's really for scripts). Cons: Users lose the benefit of not having to use any characters for line continuance. + Here's another alternative sigil to do the same thing that is a bit more literal: + + ```PowerShell + New-ADUser ... + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + -UserPrincipalName 'J.Robinson@enterprise.com' + -Path 'OU=Users,DC=enterprise,DC=com' + -AccountPassword (Read-Host -AsSecureString 'Input Password') + -Enabled $true + ``` + + Pros: ... is literal and familiar. The same PSReadline benefits listed for the previous example apply. + Cons: The same cons listed in the previous example apply. + 1. Add support for optional features to PowerShell, and make this feature optional, rather than experimental. The experimental feature is designed to be a temporary holding place until features are fully developed. There are advantages to having optional features as well, which users can opt into if they want the benefit. Ideally such functionality would have support for enabling optional features in both scripts and modules, so that the features could be used by script/module authors without impacting the experience of individual consumers of those scripts/modules. This alone (support for optional features) warrants another RFC, but assuming it is there and assuming such features can be turned on for scripts (via `#requires`?) and/or modules (via the manifest), scripters who want this capability could have it automatically turned on for new scripts/modules without risk to existing scripts/modules because they wouldn't have that feature enabled, thus preventing a breaking change. Anyone who wants this for existing scripts/modules could manually enable it and take on the responsibility of making their code work appropriately. Pros: Allows the feature to be used without any breaking changes, and without extra continuance characters. Cons: Requires optional feature work in PowerShell (an RFC that I'd be happy to write). + +1. Add argument enclosure support to PowerShell. + + One reader of this RFC who expressed their dislike for this functionality was pointing out that they don't like the fact that there is no terminator to the wrapped command parameters, so PowerShell needs to determine when the command ends based on lookahead. If preferable, new syntax could be added to allow for argument enclosures so that there is a defined terminator. For example, consider this syntax: + + ```PowerShell + New-ADUser -{ + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + -UserPrincipalName 'J.Robinson@enterprise.com' + -Path 'OU=Users,DC=enterprise,DC=com' + -AccountPassword (Read-Host -AsSecureString 'Input Password') + -Enabled $true + } + ``` + + What's interesting about this syntax is that these don't need to be just (named) parameter enclosures. They can be defined as argument enclosures, allowing scripters to put whatever they want on whichever lines they want, wrapping where it makes sense for them to do so, while using named parameters, positional parameters, or arguments (for external commands that don't have parameters). + + Pros: Allows the feature to be used without any breaking changes (script blocks do not support negate or subtraction operators, so this new enclosure could be added without risk). Allows the scripter to wrap how they see fit, while still getting Intellisense and tab completion. Parameters and arguments are entered the same way they would be if they were all placed on one line (e.g. unlike splatting, parameter names are entered with dashes, no equals signs are required, etc.). + Cons: Requires a little extra syntax to make it work properly. + From f84afbb2a8d68651db57c2c272ee221e4095932b Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Mon, 20 May 2019 12:17:30 -0300 Subject: [PATCH 07/22] formatting changes --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 40 ++++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index 6d14df0b..0b316882 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -174,8 +174,14 @@ If the risk is deemed to be too high because of the risk with named unary operat -Enabled $true ``` - Pros: The @ symbol is familiar since it is used for splatting. Also, PSReadline could recognize when you're opting in to use this at the command prompt, only running the command if you hit enter twice (although this wouldn't be used nearly as often at the prompt -- it's really for scripts). - Cons: Users lose the benefit of not having to use any characters for line continuance. + **Pros:** + + * the @ symbol is familiar since it is used for splatting + * PSReadline could recognize when you're opting in to use this at the command prompt, only running the command if you hit enter twice (although this wouldn't be used nearly as often at the prompt -- it's really for scripts). + + **Cons:** + + * Users lose the benefit of not having to use any characters for line continuance. Here's another alternative sigil to do the same thing that is a bit more literal: @@ -191,15 +197,26 @@ If the risk is deemed to be too high because of the risk with named unary operat -Enabled $true ``` - Pros: ... is literal and familiar. The same PSReadline benefits listed for the previous example apply. - Cons: The same cons listed in the previous example apply. + **Pros:** + + * ... is literal and familiar + * the same PSReadline benefits listed for the previous example apply. + + **Cons:** + + * the same cons listed in the previous example apply. 1. Add support for optional features to PowerShell, and make this feature optional, rather than experimental. The experimental feature is designed to be a temporary holding place until features are fully developed. There are advantages to having optional features as well, which users can opt into if they want the benefit. Ideally such functionality would have support for enabling optional features in both scripts and modules, so that the features could be used by script/module authors without impacting the experience of individual consumers of those scripts/modules. This alone (support for optional features) warrants another RFC, but assuming it is there and assuming such features can be turned on for scripts (via `#requires`?) and/or modules (via the manifest), scripters who want this capability could have it automatically turned on for new scripts/modules without risk to existing scripts/modules because they wouldn't have that feature enabled, thus preventing a breaking change. Anyone who wants this for existing scripts/modules could manually enable it and take on the responsibility of making their code work appropriately. - Pros: Allows the feature to be used without any breaking changes, and without extra continuance characters. - Cons: Requires optional feature work in PowerShell (an RFC that I'd be happy to write). + **Pros:** + + * allows the feature to be used without any breaking changes, and without extra continuance characters. + + **Cons:** + + * requires optional feature work in PowerShell (an RFC that I'd be happy to write). 1. Add argument enclosure support to PowerShell. @@ -220,6 +237,13 @@ If the risk is deemed to be too high because of the risk with named unary operat What's interesting about this syntax is that these don't need to be just (named) parameter enclosures. They can be defined as argument enclosures, allowing scripters to put whatever they want on whichever lines they want, wrapping where it makes sense for them to do so, while using named parameters, positional parameters, or arguments (for external commands that don't have parameters). - Pros: Allows the feature to be used without any breaking changes (script blocks do not support negate or subtraction operators, so this new enclosure could be added without risk). Allows the scripter to wrap how they see fit, while still getting Intellisense and tab completion. Parameters and arguments are entered the same way they would be if they were all placed on one line (e.g. unlike splatting, parameter names are entered with dashes, no equals signs are required, etc.). - Cons: Requires a little extra syntax to make it work properly. + **Pros:** + + * allows the feature to be used without any breaking changes (script blocks do not support negate or subtraction operators, so this new enclosure could be added without risk) + * allows the scripter to wrap how they see fit, while still getting Intellisense and tab completion. P + * parameters and arguments are entered the same way they would be if they were all placed on one line (e.g. unlike splatting, parameter names are entered with dashes, no equals signs are required, etc.). + + **Cons:** + + * requires a little extra syntax to make it work properly. From 7211f19de56ed1209ab14aa3bbb528169edd1e0d Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Mon, 20 May 2019 12:28:27 -0300 Subject: [PATCH 08/22] cleaned up wording to keep focus on the intent of the RFC --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 34 ++++---------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index 0b316882..bab6765d 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -9,35 +9,15 @@ Comments Due: June 16, 2019 Plan to implement: Yes --- -# Support implicit line continuance when using named parameters or splatting in commands +# Support implicit line continuance when using named parameters, splatting, or the stop parsing sigil in commands -Nobody likes having to use the backtick to wrap commands in PowerShell, yet many users still use it to get the style they prefer in their scripts. - -For example, PowerShell has long supported explicit line continuance when you end a pipelined command line with a pipe symbol, like this: - -```PowerShell -Get-Process -Id $PID | - Stop-Process -``` - -Even though that is available, when you have a pipeline with many stages (commands) in it, the style is not as desirable as it could be if you could place the pipeline on the beginning of the line instead, like this: - -```PowerShell -Get-Process -Id $PID - | Stop-Process -``` - -Historically that syntax would not be possible unless you ended each line before the last line in the pipeline with a backtick. That shouldn't be necessary though, and PowerShell should be smart enough to recognize implicit line continuance when pipelines are placed at the beginning of the line. This was discussed in detail in [Issue #3020](https://github.com/PowerShell/PowerShell/issues/3020), and [PR #8938](https://github.com/PowerShell/PowerShell/pull/8938) that was recently merged added this support to PowerShell for version 7. - -While that is helpful, there is another potential improvement where PowerShell could support implicit line continuance: when using named parameters or splatting in commands, and that's what this RFC is about. - -For example, consider this example of a New-ADUser command invocation: +Consider this example of a New-ADUser command invocation: ```PowerShell New-ADUser -Name 'Jack Robinson' -GivenName 'Jack' -Surname 'Robinson' -SamAccountName 'J.Robinson' -UserPrincipalName 'J.Robinson@enterprise.com' -Path 'OU=Users,DC=enterprise,DC=com' -AccountPassword (Read-Host -AsSecureString 'Input Password') -Enabled $true ``` -By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage. To wrap this command across multiple lines, users can either use backticks, or they can use splatting. The former is a nuisance which should really only be used in situations when PowerShell cannot implicitly intuit how lines are wrapped. The latter is helpful, but users lose the benefits of tab completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's generally onerous. Even though Visual Studio Code has an extension that makes splatting easier, as can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense for future updates unless you work from the command first and then add to your splatted collection, and that's just in Visual Studio Code. Other editors may or may not support that functionality, and users working in a standalone terminal won't have that available to them either. +By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage. To wrap this command across multiple lines, users can either use backticks, or they can use splatting. The former is a syntactical nuisance which should really only be used in situations when PowerShell cannot implicitly intuit how lines are wrapped. The latter is helpful, but users lose the benefits of tab completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's onerous. Even though Visual Studio Code has an extension that makes splatting easier, as can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense for future updates unless you work from the command first and then add to your splatted collection, and that's just in Visual Studio Code. Other editors may or may not support that functionality, and users working in a standalone terminal won't have that available to them either. Instead, why not allow users to do this by supporting implicit line continuance when using named parameters: @@ -82,12 +62,12 @@ For the last one, `--%` stops the parsing of that command, so no further implici ## Motivation As a script/module author, - I can wrap long commands across multiple lines at any named parameter or splatted collection, - so that my scripts are easier to maintain while I still get the benefits of Intellisense and tab completion. + I can wrap long commands across multiple lines at any named parameter, splatted collection, or the stop-parsing sigil + so that my scripts are easier to write and maintain while I still get the benefits of Intellisense and tab completion. ## Specification -Note: This RFC is already implemented and submitted as [PR #9614](https://github.com/PowerShell/PowerShell/pull/9614). +Note: This RFC is already implemented and submitted as [PR #9614](https://github.com/PowerShell/PowerShell/pull/9614) in case you want to try it out early and see what it's like. Since this RFC includes some breaking changes (see below), it will be initially implemented with the `PSImplicitLineContinuanceForNamedParameters` experimental feature flag. If the PowerShell Team and the community agree that the risk of this breaking change is low enough, and the workaround is sufficient for those low frequency use cases where it does become an issue, I would much prefer not using an experimental feature flag at all. @@ -137,7 +117,7 @@ To fix this, users can do one of the following: -split 'a b c d' # splits the string 'a b c d' into an array with four items ``` -1. In the example with a command that starts with a dash, invoke the command using the call operator, as shown here: +2. In the example with a command that starts with a dash, invoke the command using the call operator, as shown here: ```PowerShell function -dash { From 65e4ba3388582139020af0211416e85b21cea90f Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Wed, 22 May 2019 09:26:15 -0300 Subject: [PATCH 09/22] correction of misleading wording --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index bab6765d..c962bab0 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -57,7 +57,7 @@ And lastly, if users have a bunch of arguments they want to pass after the stop --% $Hostname -l $Username -pw $Password $Command ``` -For the last one, `--%` stops the parsing of that command, so no further implicit line continuance may be used because that would require the parser which the scripter opted out of using for that command. +For the last one, `--%` stops the parsing of that command until a newline or a pipe is encountered, so no further parameter line continuance could be used because that would require the parser which the scripter opted out of using for that command. ## Motivation From bbc4c0a01959f465a7bcfae74a42514d6c8180be Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Wed, 22 May 2019 21:10:23 -0300 Subject: [PATCH 10/22] reworked RFC based on comments/discussion --- 1-Draft/RFCNNNN-Implicit-Line-Continuance.md | 217 +++++-------------- 1 file changed, 51 insertions(+), 166 deletions(-) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md index c962bab0..5f76b919 100644 --- a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Implicit-Line-Continuance.md @@ -9,7 +9,7 @@ Comments Due: June 16, 2019 Plan to implement: Yes --- -# Support implicit line continuance when using named parameters, splatting, or the stop parsing sigil in commands +# Multi-line continuance for commands Consider this example of a New-ADUser command invocation: @@ -17,12 +17,12 @@ Consider this example of a New-ADUser command invocation: New-ADUser -Name 'Jack Robinson' -GivenName 'Jack' -Surname 'Robinson' -SamAccountName 'J.Robinson' -UserPrincipalName 'J.Robinson@enterprise.com' -Path 'OU=Users,DC=enterprise,DC=com' -AccountPassword (Read-Host -AsSecureString 'Input Password') -Enabled $true ``` -By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage. To wrap this command across multiple lines, users can either use backticks, or they can use splatting. The former is a syntactical nuisance which should really only be used in situations when PowerShell cannot implicitly intuit how lines are wrapped. The latter is helpful, but users lose the benefits of tab completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's onerous. Even though Visual Studio Code has an extension that makes splatting easier, as can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense for future updates unless you work from the command first and then add to your splatted collection, and that's just in Visual Studio Code. Other editors may or may not support that functionality, and users working in a standalone terminal won't have that available to them either. +By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage. To wrap this command across multiple lines, users can either use backticks or they can use splatting. The former is a syntactical nuisance which should really only be used in situations when no other option is available. The latter is helpful, but it puts the parameters before the command, making it more difficult for less experienced users to learn/use, and all scripters lose the benefits of tab completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's onerous. Even though Visual Studio Code has an extension that makes splatting easier, as can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense for future updates unless you work from the command first and then add to your splatted collection, and that's just in Visual Studio Code. Other editors may or may not support that functionality, and users working in a standalone terminal won't have that available to them either. -Instead, why not allow users to do this by supporting implicit line continuance when using named parameters: +Instead, why not allow users to wrap commands across multiple lines in a more intuitive way without having to deal with backticks on every line or splatting, like this: ```PowerShell -New-ADUser +New-ADUser @ -Name 'Jack Robinson' -GivenName 'Jack' -Surname 'Robinson' @@ -31,199 +31,84 @@ New-ADUser -Path 'OU=Users,DC=enterprise,DC=com' -AccountPassword (Read-Host -AsSecureString 'Input Password') -Enabled $true -``` -Further, if they have some parameters they want to splat in (because splatting is not just about shortening lines -- it's very useful for users to apply common parameters/values to multiple commands), let them do this as well: +Get-ChildItem @ + $rootFolder + -File + -Filter '*.ps*1' -```PowerShell -$commonParams = @{ - Path = 'OU=Users,DC=enterprise,DC=com' - Enabled = $true -} -New-ADUser - -Name 'Jack Robinson' - -GivenName 'Jack' - -Surname 'Robinson' - -SamAccountName 'J.Robinson' - -UserPrincipalName 'J.Robinson@enterprise.com' - -AccountPassword (Read-Host -AsSecureString 'Input Password') - @commonParams ``` -And lastly, if users have a bunch of arguments they want to pass after the stop parsing sigil (`--%`), let them do this also (thanks @Jaykul for the suggestion): +Of course, they could invoke external commands and pass through arguments this way as well: ```PowerShell -&"./plink.exe" +& "./plink.exe" @ --% $Hostname -l $Username -pw $Password $Command -``` - -For the last one, `--%` stops the parsing of that command until a newline or a pipe is encountered, so no further parameter line continuance could be used because that would require the parser which the scripter opted out of using for that command. - -## Motivation - - As a script/module author, - I can wrap long commands across multiple lines at any named parameter, splatted collection, or the stop-parsing sigil - so that my scripts are easier to write and maintain while I still get the benefits of Intellisense and tab completion. -## Specification - -Note: This RFC is already implemented and submitted as [PR #9614](https://github.com/PowerShell/PowerShell/pull/9614) in case you want to try it out early and see what it's like. - -Since this RFC includes some breaking changes (see below), it will be initially implemented with the `PSImplicitLineContinuanceForNamedParameters` experimental feature flag. If the PowerShell Team and the community agree that the risk of this breaking change is low enough, and the workaround is sufficient for those low frequency use cases where it does become an issue, I would much prefer not using an experimental feature flag at all. - -For the implementation, this RFC builds on the work done in [PR #8938](https://github.com/PowerShell/PowerShell/pull/8938), evolving the logic used in the tokenizer that supports implicit line continuance for lines starting with a pipe such that it can be used to check for implicit line continuance for named parameters and splatted collections as well. To keep performance optimal, the parser logic that identifies command parameters where the implicit line continuance checks will be invoked will recognize if a pipe is found on a subsequent line as well, to ensure the lookahead logic is only invoked once per line in commands/pipelines. - -## Alternate Proposals and Considerations - -While implicit line continuance for splatted collections is not a breaking change (PowerShell syntax does not support `@variableName` at the start of a command), implicit line continuance for named parameters is a breaking change in some scenarios, because PowerShell syntax currently supports commands that start with dash, and PowerShell supports unary operators whose name starts with a single dash. +cacls @ + c:\docs\work + /E /T /C /G + "FinanceUsers":F -For example, consider this script: - -```PowerShell -function -dash { - 'run' -} - -Get-Process -Id $PID --dash ``` -In PowerShell 6.x and earlier, two commands will be executed: `Get-Process`, and `-dash`. With this PR in place and the experimental feature enabled, only one command would be executed: `Get-Process`. The reason is that the parser would identify `-dash` as being intended as a parameter on the command on the previous line. That's how the parser needs to work to make this implicit line continuance functional. - -Similarly, consider this script: - -```PowerShell -Get-Process -Id $PID --split 'a b c d' -``` +In each of these examples, the command parsing stops when one of the following is found: -Similar to the previous example, in PowerShell 6.x and earlier, one command and one statement will be executed: `Get-Process`, and the unary `-split` statement. With this PR in place and the experimental feature enabled, only one command would be executed: `Get-Process`, because again, the parser would identify `-split` as being intended as a parameter on the command on the previous line. The same applies to the `-join` unary operator as well. It does not apply to the `--` prefix arithmetic operator because the parser knows parameter names cannot start with a dash. +* end of file +* blank line +* command-terminating token -To fix this, users can do one of the following: +The pros/cons to this new syntax are as follows: -1. For either example, insert a blank line between `Get-Process` and the next command that starts with dash, as shown here: +**Pros:** - ```PowerShell - function -dash { - 'run' - } +* allows the scripter to wrap commands how they see fit, while still getting Intellisense and tab completion, without using backticks. +* parameters and arguments are entered the exact same way they would be if they were all placed on one line. +* ad hoc could support this syntax as well (PSReadline could wait for a double-enter when in multi-line command parsing mode) +* no breaking changes (a standalone @ is currently an unrecognized token in PowerShell no matter where it is used). - Get-Process -Id $PID +**Cons:** - -dash # Runs the -dash command because implicit line continuance stops looking when it encounters a blank line +* if no command-terminating token is used to terminate the command, a blank line is required after the command as terminator (but, users can opt to use a semi-colon or some other command-terminating token if they don't want the blank line) - Get-Process -Id $PID - - -split 'a b c d' # splits the string 'a b c d' into an array with four items - ``` - -2. In the example with a command that starts with a dash, invoke the command using the call operator, as shown here: - - ```PowerShell - function -dash { - 'run' - } - - Get-Process -Id $PID - & -dash # Runs the `-dash` command because implicit line continuance sees the call operator and recognizes that the line does not continue further - ``` - - Unfortunately this workaround does not work for the -split or -join unary operators, because you cannot invoke statement that starts with a unary operator with the call operator (the call operator is only for invoking commands). - -In practice, I believe that there are not many commands out there that start with a dash. While researching this, I couldn't find a single command on Windows or Linux that starts with a dash, so that's not a very risky scenario. However, since the `-split` and `-join` unary operators exist in PowerShell, there is a good likelihood that those may be used on a line following a command, and that is where this breaking change would have the most potential impact. While I don't feel that risk is enough to reject this proposal entirely, because it adds significant value to script authors, it is worth considering what the best approach would be. - -Special casing the named unary operators could work (among the thousands of commands on my system, none of them have split or join parameters, but some may exist somewhere), but that would mean future unary operators be special cased as well, so that approach isn't desirable because it risks future breaking changes. - -If the risk is deemed to be too high because of the risk with named unary operators, at a bare minimum I feel this feature offers enough significant value to the community that it should not be rejected, but instead offered as an optional feature so that users wanting the benefit can opt-into the functionality, and mark it as enabled for their scripts/modules. I also suspect the majority of scripters would want it turned on and would then simply write their scripts accordingly. It's really too bad though that unary operators with string names use the same single first character as parameter names because they get in the way here. In hindsight, named operators should probably have been prefixed with something other than a single dash to differentiate them from named parameters (something to consider if PowerShell ever comes out with a version with significant breaking changes plus conversion scripts). - -### Some Non-Breaking Alternatives - -1. Require users to opt-in on any command where they want this wrapping by ending the first line (and only the first line) with a sigil. - - This suggestion was proposed by @jaykul. We could add a token at the end of a command and from that point on, treat subsequent lines as part of the same command if they begin with named parameters, splatted collections, or the stop-parsing sigil (`--%`). For example, this could be a multi-line command that follows these rules: - - ```PowerShell - New-ADUser @ - -Name 'Jack Robinson' - -GivenName 'Jack' - -Surname 'Robinson' - -SamAccountName 'J.Robinson' - -UserPrincipalName 'J.Robinson@enterprise.com' - -Path 'OU=Users,DC=enterprise,DC=com' - -AccountPassword (Read-Host -AsSecureString 'Input Password') - -Enabled $true - ``` - - **Pros:** - - * the @ symbol is familiar since it is used for splatting - * PSReadline could recognize when you're opting in to use this at the command prompt, only running the command if you hit enter twice (although this wouldn't be used nearly as often at the prompt -- it's really for scripts). - - **Cons:** - - * Users lose the benefit of not having to use any characters for line continuance. - - Here's another alternative sigil to do the same thing that is a bit more literal: - - ```PowerShell - New-ADUser ... - -Name 'Jack Robinson' - -GivenName 'Jack' - -Surname 'Robinson' - -SamAccountName 'J.Robinson' - -UserPrincipalName 'J.Robinson@enterprise.com' - -Path 'OU=Users,DC=enterprise,DC=com' - -AccountPassword (Read-Host -AsSecureString 'Input Password') - -Enabled $true - ``` - - **Pros:** - - * ... is literal and familiar - * the same PSReadline benefits listed for the previous example apply. - - **Cons:** +## Motivation - * the same cons listed in the previous example apply. + As a script/module author, + I can wrap commands across multiple lines easily and intuitively without backticks or splatting + so that my scripts remain easy to write and maintain while still giving me the benefits of Intellisense and tab completion. -1. Add support for optional features to PowerShell, and make this feature optional, rather than experimental. +## Specification - The experimental feature is designed to be a temporary holding place until features are fully developed. There are advantages to having optional features as well, which users can opt into if they want the benefit. Ideally such functionality would have support for enabling optional features in both scripts and modules, so that the features could be used by script/module authors without impacting the experience of individual consumers of those scripts/modules. This alone (support for optional features) warrants another RFC, but assuming it is there and assuming such features can be turned on for scripts (via `#requires`?) and/or modules (via the manifest), scripters who want this capability could have it automatically turned on for new scripts/modules without risk to existing scripts/modules because they wouldn't have that feature enabled, thus preventing a breaking change. Anyone who wants this for existing scripts/modules could manually enable it and take on the responsibility of making their code work appropriately. +* expand the command parser to accept multi-line command parameters/arguments after an at symbol (`@`) is encountered at the end of a line +* terminate multi-line commands when the parser encounters either a blank line or a command-terminating token (pipe symbol, redirection operator, closing enclosure, or semi-colon when not used after a stop-parsing sigil, or simply pipe symbol or redirection operator when used after a stop-parsing sigil) - **Pros:** +## Alternate Proposals and Considerations - * allows the feature to be used without any breaking changes, and without extra continuance characters. +### A different sigil - **Cons:** +The original draft of this RFC included different options for the sigil that could be used to enter multi-line parameter/argument parsing mode, and others were presented in the discussion however none of the other sigils that were presented could be used without breaking changes. When considering an alternate sigil, it must be something that can be identified as a unique token without breaking commands such as Write-Host (which can write many sigils to the console) or commands external to PowerShell. - * requires optional feature work in PowerShell (an RFC that I'd be happy to write). +### Enclosures instead of a sigil -1. Add argument enclosure support to PowerShell. +The original draft also included some proposals for enclosures instead of a leading sigil. While it may seem up front that enclosures make good sense, some thought needs to be given to the stop-parsing sigil, which causes PowerShell to treat closing enclosures as arguments for a command. - One reader of this RFC who expressed their dislike for this functionality was pointing out that they don't like the fact that there is no terminator to the wrapped command parameters, so PowerShell needs to determine when the command ends based on lookahead. If preferable, new syntax could be added to allow for argument enclosures so that there is a defined terminator. For example, consider this syntax: +For example, consider this syntax: - ```PowerShell - New-ADUser -{ - -Name 'Jack Robinson' - -GivenName 'Jack' - -Surname 'Robinson' - -SamAccountName 'J.Robinson' - -UserPrincipalName 'J.Robinson@enterprise.com' - -Path 'OU=Users,DC=enterprise,DC=com' - -AccountPassword (Read-Host -AsSecureString 'Input Password') - -Enabled $true - } - ``` +```PowerShell +. {cmd --% dir} +``` - What's interesting about this syntax is that these don't need to be just (named) parameter enclosures. They can be defined as argument enclosures, allowing scripters to put whatever they want on whichever lines they want, wrapping where it makes sense for them to do so, while using named parameters, positional parameters, or arguments (for external commands that don't have parameters). +That command will not parse because there is no closing brace for the script block because what appears to be a closing brace is placed after the stop-parsing sigil. To correct this, the closing brace must be placed on a separate line, but in a multi-line command you cannot do that (because the command is multi-line, so where would the parser terminate after a stop-parsing sigil) and therefore, unless the sigil used to identify the end of the multi-line parameter/arguments was one that could be respected by the stop-parsing sigil, and safely be introduced without risk to breaking changes, enclosures simply cannot be used. - **Pros:** +### Inline splatting - * allows the feature to be used without any breaking changes (script blocks do not support negate or subtraction operators, so this new enclosure could be added without risk) - * allows the scripter to wrap how they see fit, while still getting Intellisense and tab completion. P - * parameters and arguments are entered the same way they would be if they were all placed on one line (e.g. unlike splatting, parameter names are entered with dashes, no equals signs are required, etc.). +There has also been some discussion about the idea of inline splatting, using a format like `-@{...}` or `-@(...)`. Inline splatting has also been discussed separately on [RFC0002: Generalized Splatting](https://github.com/PowerShell/PowerShell-RFC/blob/master/2-Draft-Accepted/RFC0002-Generalized-Splatting.md), but using the syntax `@@{...}` or `@@(...)`. Using splatting to be able to span a single command across multiple lines has several limitations, including: - **Cons:** +1. You cannot transition to/from the inline splatted syntax without a bunch of manual tweaks to the command (either converting parameter syntax into hashtable or array syntax or vice versa). +1. You're forced to choose between named parameters or positional parameters/arguments. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two. +1. There's no way to include unparsed arguments after the stop-parsing sigil in splatting. +1. Splatting requires a different syntax than typical parameter/argument input, which is more to learn. In contrast, the proposal above only requires learning about the `@` sigil (borrowed from splatting, but without specifying hashtables or arrays -- just allow all content until a newline), reducing the learning curve and allowing users to use parameters the same way in either case. - * requires a little extra syntax to make it work properly. +### Breaking changes +All previous options that would have introduced breaking changes have been removed in favor of a syntax that just works to the specification without any breaking changes, regardless of how you use it. From e23bd9dba9d2450a68caf0015baf98490e9b34aa Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Wed, 22 May 2019 21:11:52 -0300 Subject: [PATCH 11/22] renamed RFC to match most recent proposal --- ...tinuance.md => RFCNNNN-Multi-Line-Continuance-For-Commands.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 1-Draft/{RFCNNNN-Implicit-Line-Continuance.md => RFCNNNN-Multi-Line-Continuance-For-Commands.md} (100%) diff --git a/1-Draft/RFCNNNN-Implicit-Line-Continuance.md b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md similarity index 100% rename from 1-Draft/RFCNNNN-Implicit-Line-Continuance.md rename to 1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md From 2c3339f67fa960f78f639ce1a52e9bba46d49b37 Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Wed, 22 May 2019 21:30:36 -0300 Subject: [PATCH 12/22] cleaned up wording --- ...NNN-Multi-Line-Continuance-For-Commands.md | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md index 5f76b919..e1621e31 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md @@ -52,7 +52,7 @@ cacls @ ``` -In each of these examples, the command parsing stops when one of the following is found: +In each of these examples, the parser starts parsing the command as a multi-line command when it encounters the `@` token at the end of the line, and in this mode command parsing stops once one of the following is found: * end of file * blank line @@ -80,7 +80,7 @@ The pros/cons to this new syntax are as follows: ## Specification * expand the command parser to accept multi-line command parameters/arguments after an at symbol (`@`) is encountered at the end of a line -* terminate multi-line commands when the parser encounters either a blank line or a command-terminating token (pipe symbol, redirection operator, closing enclosure, or semi-colon when not used after a stop-parsing sigil, or simply pipe symbol or redirection operator when used after a stop-parsing sigil) +* terminate multi-line commands when the parser encounters either a blank line or a command-terminating token (a command-terminating token will be a pipe symbol, redirection operator, closing enclosure, or semi-colon when the command does not have the stop-parsing sigil in its arguments, or simply pipe symbol or redirection operator the command does have the stop-parsing sigil in its arguments) ## Alternate Proposals and Considerations @@ -102,13 +102,23 @@ That command will not parse because there is no closing brace for the script blo ### Inline splatting -There has also been some discussion about the idea of inline splatting, using a format like `-@{...}` or `-@(...)`. Inline splatting has also been discussed separately on [RFC0002: Generalized Splatting](https://github.com/PowerShell/PowerShell-RFC/blob/master/2-Draft-Accepted/RFC0002-Generalized-Splatting.md), but using the syntax `@@{...}` or `@@(...)`. Using splatting to be able to span a single command across multiple lines has several limitations, including: +There has also been some discussion about the idea of inline splatting, using a format like `-@{...}` or `-@(...)`. Inline splatting has also been discussed separately on [RFC0002: Generalized Splatting](https://github.com/PowerShell/PowerShell-RFC/blob/master/2-Draft-Accepted/RFC0002-Generalized-Splatting.md), but using the syntax `@@{...}` or `@@(...)`. Here is an example showing what that might look like: + +```PowerShell +Get-ChildItem -@{ + LiteralPath = $rootFolder + File = $true + Filter = '*.ps*1' +} +``` + +Using inline splatting to be able to span a single command across multiple lines like this has several limitations, including: 1. You cannot transition to/from the inline splatted syntax without a bunch of manual tweaks to the command (either converting parameter syntax into hashtable or array syntax or vice versa). -1. You're forced to choose between named parameters or positional parameters/arguments. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two. +1. You're forced to choose between named parameters or positional parameters/arguments. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two (the example shown just above is also used earlier in this RFC with positional parameters and switch parameters used without values, matching the way it is often used as a single-line command). 1. There's no way to include unparsed arguments after the stop-parsing sigil in splatting. 1. Splatting requires a different syntax than typical parameter/argument input, which is more to learn. In contrast, the proposal above only requires learning about the `@` sigil (borrowed from splatting, but without specifying hashtables or arrays -- just allow all content until a newline), reducing the learning curve and allowing users to use parameters the same way in either case. ### Breaking changes -All previous options that would have introduced breaking changes have been removed in favor of a syntax that just works to the specification without any breaking changes, regardless of how you use it. +All previous options from the original RFC and the discussion about it that would have introduced breaking changes have been removed in favor of a syntax that just works to the specification without any breaking changes, regardless of how you use it. From c60b35aa52910aea25df2dcad4726a89c79a39fe Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Wed, 22 May 2019 23:48:09 -0300 Subject: [PATCH 13/22] corrected wording --- 1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md index e1621e31..a0efb99d 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md @@ -115,8 +115,8 @@ Get-ChildItem -@{ Using inline splatting to be able to span a single command across multiple lines like this has several limitations, including: 1. You cannot transition to/from the inline splatted syntax without a bunch of manual tweaks to the command (either converting parameter syntax into hashtable or array syntax or vice versa). -1. You're forced to choose between named parameters or positional parameters/arguments. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two (the example shown just above is also used earlier in this RFC with positional parameters and switch parameters used without values, matching the way it is often used as a single-line command). -1. There's no way to include unparsed arguments after the stop-parsing sigil in splatting. +1. You're forced to choose between named parameters or positional parameters/arguments for each splatted collection. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two (the example shown just above is also used earlier in this RFC with positional parameters and switch parameters used without values, matching the way it is often used as a single-line command). +1. There's no way to include unparsed arguments after the stop-parsing sigil in splatting. You can add it afterwards, but not include it within. 1. Splatting requires a different syntax than typical parameter/argument input, which is more to learn. In contrast, the proposal above only requires learning about the `@` sigil (borrowed from splatting, but without specifying hashtables or arrays -- just allow all content until a newline), reducing the learning curve and allowing users to use parameters the same way in either case. ### Breaking changes From a45c1b8b71249fd6abd5009cd0a273091167bb1b Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Thu, 23 May 2019 00:19:18 -0300 Subject: [PATCH 14/22] responded to feedback --- ...NNN-Multi-Line-Continuance-For-Commands.md | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md index a0efb99d..6a54de57 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md @@ -52,11 +52,11 @@ cacls @ ``` -In each of these examples, the parser starts parsing the command as a multi-line command when it encounters the `@` token at the end of the line, and in this mode command parsing stops once one of the following is found: +In each of these examples, the parser starts parsing the command as a multi-line command when it encounters the `@` token as the last token on the line, and in this mode command parsing stops once one of the following is found: * end of file -* blank line -* command-terminating token +* two newlines (as opposed to the normal one) +* command-terminating token (i.e. all other ways of ending commands work the same as usual, and this does not affect other elements of the PowerShell syntax) The pros/cons to this new syntax are as follows: @@ -66,10 +66,11 @@ The pros/cons to this new syntax are as follows: * parameters and arguments are entered the exact same way they would be if they were all placed on one line. * ad hoc could support this syntax as well (PSReadline could wait for a double-enter when in multi-line command parsing mode) * no breaking changes (a standalone @ is currently an unrecognized token in PowerShell no matter where it is used). +* users can use a blank line to terminate the command, or they can opt to use a semi-colon or some other valid command-terminating token instead. **Cons:** -* if no command-terminating token is used to terminate the command, a blank line is required after the command as terminator (but, users can opt to use a semi-colon or some other command-terminating token if they don't want the blank line) +* no known cons at this time ## Motivation @@ -86,7 +87,7 @@ The pros/cons to this new syntax are as follows: ### A different sigil -The original draft of this RFC included different options for the sigil that could be used to enter multi-line parameter/argument parsing mode, and others were presented in the discussion however none of the other sigils that were presented could be used without breaking changes. When considering an alternate sigil, it must be something that can be identified as a unique token without breaking commands such as Write-Host (which can write many sigils to the console) or commands external to PowerShell. +The original draft of this RFC included different options for the sigil that could be used to enter multi-line parameter/argument parsing mode, and others were presented in the discussion however none of the other sigils that were presented could be used without breaking changes. When considering an alternate sigil, it must be something that can be identified as a unique token without breaking commands that accept multiple strings as positional parameters, such as Write-Host (which can write many sigils to the console) or commands external to PowerShell. ### Enclosures instead of a sigil @@ -95,10 +96,15 @@ The original draft also included some proposals for enclosures instead of a lead For example, consider this syntax: ```PowerShell -. {cmd --% dir} +. {"./plink.exe" @ + --% + $Hostname + -l $Username + -pw $Password + $Command} ``` -That command will not parse because there is no closing brace for the script block because what appears to be a closing brace is placed after the stop-parsing sigil. To correct this, the closing brace must be placed on a separate line, but in a multi-line command you cannot do that (because the command is multi-line, so where would the parser terminate after a stop-parsing sigil) and therefore, unless the sigil used to identify the end of the multi-line parameter/arguments was one that could be respected by the stop-parsing sigil, and safely be introduced without risk to breaking changes, enclosures simply cannot be used. +That command will not parse because there is no closing brace for the script block. What appears to be a closing brace is placed after the stop-parsing sigil, and therefore treated as an argument to the plink command. To correct this, the closing brace must be placed on a separate line, but in a multi-line command you cannot do that (because the command is multi-line, so where would the parser terminate after a stop-parsing sigil) and therefore, unless the sigil used to identify the end of the multi-line parameter/arguments was one that could be respected by the stop-parsing sigil, and safely be introduced without risk to breaking changes, enclosures simply cannot be used. ### Inline splatting @@ -119,6 +125,8 @@ Using inline splatting to be able to span a single command across multiple lines 1. There's no way to include unparsed arguments after the stop-parsing sigil in splatting. You can add it afterwards, but not include it within. 1. Splatting requires a different syntax than typical parameter/argument input, which is more to learn. In contrast, the proposal above only requires learning about the `@` sigil (borrowed from splatting, but without specifying hashtables or arrays -- just allow all content until a newline), reducing the learning curve and allowing users to use parameters the same way in either case. +Further, unlike using a leading sigil such as `@`, which would work with Intellisense and tab expansion as they are coded now, inline splatting would require special work to make Intellisense and tab expansion work with it. That's not a reason not to do it, but it is more code to write/maintain. + ### Breaking changes All previous options from the original RFC and the discussion about it that would have introduced breaking changes have been removed in favor of a syntax that just works to the specification without any breaking changes, regardless of how you use it. From aa0b5ce8aa61da433a186104a03404e725102ab0 Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Thu, 23 May 2019 00:22:40 -0300 Subject: [PATCH 15/22] more feedback --- .../RFCNNNN-Multi-Line-Continuance-For-Commands.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md index 6a54de57..cd5cbc6c 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md @@ -81,7 +81,11 @@ The pros/cons to this new syntax are as follows: ## Specification * expand the command parser to accept multi-line command parameters/arguments after an at symbol (`@`) is encountered at the end of a line -* terminate multi-line commands when the parser encounters either a blank line or a command-terminating token (a command-terminating token will be a pipe symbol, redirection operator, closing enclosure, or semi-colon when the command does not have the stop-parsing sigil in its arguments, or simply pipe symbol or redirection operator the command does have the stop-parsing sigil in its arguments) +* terminate multi-line commands when the parser encounters two newlines (rather than one), or when the parser encounters any other normal command-terminating token + +Note: +* for commands that do not use the stop-parsing sigil in their arguments, command-terminating tokens include a pipe symbol, a redirection operator, a closing enclosure, or a semi-colon. +* for commands that do use the stop-parsing sigil in their arguments, command-terminating tokens include a pipe symbol or a redirection operator. ## Alternate Proposals and Considerations @@ -121,9 +125,9 @@ Get-ChildItem -@{ Using inline splatting to be able to span a single command across multiple lines like this has several limitations, including: 1. You cannot transition to/from the inline splatted syntax without a bunch of manual tweaks to the command (either converting parameter syntax into hashtable or array syntax or vice versa). -1. You're forced to choose between named parameters or positional parameters/arguments for each splatted collection. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two (the example shown just above is also used earlier in this RFC with positional parameters and switch parameters used without values, matching the way it is often used as a single-line command). -1. There's no way to include unparsed arguments after the stop-parsing sigil in splatting. You can add it afterwards, but not include it within. -1. Splatting requires a different syntax than typical parameter/argument input, which is more to learn. In contrast, the proposal above only requires learning about the `@` sigil (borrowed from splatting, but without specifying hashtables or arrays -- just allow all content until a newline), reducing the learning curve and allowing users to use parameters the same way in either case. +2. You're forced to choose between named parameters or positional parameters/arguments for each splatted collection. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two (the example shown just above is also used earlier in this RFC with positional parameters and switch parameters used without values, matching the way it is often used as a single-line command). +3. There's no way to include unparsed arguments after the stop-parsing sigil in splatting. You can add it afterwards, but not include it within. +4. Splatting requires a different syntax than typical parameter/argument input, which is more to learn. In contrast, the proposal above only requires learning about the `@` sigil (borrowed from splatting, but without specifying hashtables or arrays -- just allow all content until a newline), reducing the learning curve and allowing users to use parameters the same way in either case. Further, unlike using a leading sigil such as `@`, which would work with Intellisense and tab expansion as they are coded now, inline splatting would require special work to make Intellisense and tab expansion work with it. That's not a reason not to do it, but it is more code to write/maintain. From 40ba3687f7139d91d6ca861b45a3ef6ba12236d6 Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Mon, 10 Jun 2019 11:51:03 -0300 Subject: [PATCH 16/22] Add alternate proposal --- ...NNN-Multi-Line-Continuance-For-Commands.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md index cd5cbc6c..275192f1 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md @@ -110,6 +110,40 @@ For example, consider this syntax: That command will not parse because there is no closing brace for the script block. What appears to be a closing brace is placed after the stop-parsing sigil, and therefore treated as an argument to the plink command. To correct this, the closing brace must be placed on a separate line, but in a multi-line command you cannot do that (because the command is multi-line, so where would the parser terminate after a stop-parsing sigil) and therefore, unless the sigil used to identify the end of the multi-line parameter/arguments was one that could be respected by the stop-parsing sigil, and safely be introduced without risk to breaking changes, enclosures simply cannot be used. +### Allowing multi-line continuance for more than just commands + +Aside from easier multi-line wrapping parameters/arguments, there are scenarios where it would be useful to have easier multi-line wrapping for other statements as well, and some members of the community have [requested support for these scenarios](https://github.com/PowerShell/PowerShell/issues/9813). PowerShell currently supports line wrapping for objects when the line ends with the dot-reference operator, like this: + +```PowerShell +$string. + ToUpper(). + Trim(). + Length +``` + +Other languages like C#, where an explicit line terminator is used, allow users to wrap such lines with the dot-reference operator at the beginning of a line, which looks something like this: + +```PowerShell +$string + .ToUpper() + .Trim() + .Length +``` + +While the Parser could handle looking ahead for methods with arguments (round brackets), there is a problem with members or with methods with no arguments (which can be invoked in PowerShell to get the method signature(s)), because you can create a function with a name that starts with a dot (e.g. `function .dot {'see?'}; .dot`). + +If we support a single sigil as a general multi-line continuance (not just for command parameters) until a statement terminator or a blank line, then we could support this syntax: + +```PowerShell +$string @ + .ToUpper() + .Trim() + .Length + +``` + +Since there is a blank line, that would just work. If it terminated with a semi-colon, that would work as well. Suddenly multi-line continuance becomes a general feature, more visible than backtick ever was, easier to use than backtick is since `@` is not an escape character, and resulting in cleaner, more elegant code that can be written to match the desired style of the author. + ### Inline splatting There has also been some discussion about the idea of inline splatting, using a format like `-@{...}` or `-@(...)`. Inline splatting has also been discussed separately on [RFC0002: Generalized Splatting](https://github.com/PowerShell/PowerShell-RFC/blob/master/2-Draft-Accepted/RFC0002-Generalized-Splatting.md), but using the syntax `@@{...}` or `@@(...)`. Here is an example showing what that might look like: From f03b2faa4351fdeb80b9b12222fdf92f43e15eb9 Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Wed, 3 Jul 2019 17:49:35 -0300 Subject: [PATCH 17/22] generalize focus, clean up formatting --- ...NNN-Multi-Line-Continuance-For-Commands.md | 170 ------------- 1-Draft/RFCNNNN-Multi-Line-Continuance.md | 234 ++++++++++++++++++ 2 files changed, 234 insertions(+), 170 deletions(-) delete mode 100644 1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md create mode 100644 1-Draft/RFCNNNN-Multi-Line-Continuance.md diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md b/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md deleted file mode 100644 index 275192f1..00000000 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance-For-Commands.md +++ /dev/null @@ -1,170 +0,0 @@ ---- -RFC: RFCnnnn -Author: Kirk Munro -Status: Draft -SupercededBy: N/A -Version: 1.0 -Area: Parser/Tokenizer -Comments Due: June 16, 2019 -Plan to implement: Yes ---- - -# Multi-line continuance for commands - -Consider this example of a New-ADUser command invocation: - -```PowerShell -New-ADUser -Name 'Jack Robinson' -GivenName 'Jack' -Surname 'Robinson' -SamAccountName 'J.Robinson' -UserPrincipalName 'J.Robinson@enterprise.com' -Path 'OU=Users,DC=enterprise,DC=com' -AccountPassword (Read-Host -AsSecureString 'Input Password') -Enabled $true -``` - -By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage. To wrap this command across multiple lines, users can either use backticks or they can use splatting. The former is a syntactical nuisance which should really only be used in situations when no other option is available. The latter is helpful, but it puts the parameters before the command, making it more difficult for less experienced users to learn/use, and all scripters lose the benefits of tab completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's onerous. Even though Visual Studio Code has an extension that makes splatting easier, as can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense for future updates unless you work from the command first and then add to your splatted collection, and that's just in Visual Studio Code. Other editors may or may not support that functionality, and users working in a standalone terminal won't have that available to them either. - -Instead, why not allow users to wrap commands across multiple lines in a more intuitive way without having to deal with backticks on every line or splatting, like this: - -```PowerShell -New-ADUser @ - -Name 'Jack Robinson' - -GivenName 'Jack' - -Surname 'Robinson' - -SamAccountName 'J.Robinson' - -UserPrincipalName 'J.Robinson@enterprise.com' - -Path 'OU=Users,DC=enterprise,DC=com' - -AccountPassword (Read-Host -AsSecureString 'Input Password') - -Enabled $true - -Get-ChildItem @ - $rootFolder - -File - -Filter '*.ps*1' - -``` - -Of course, they could invoke external commands and pass through arguments this way as well: - -```PowerShell -& "./plink.exe" @ - --% $Hostname -l $Username -pw $Password $Command - -cacls @ - c:\docs\work - /E /T /C /G - "FinanceUsers":F - -``` - -In each of these examples, the parser starts parsing the command as a multi-line command when it encounters the `@` token as the last token on the line, and in this mode command parsing stops once one of the following is found: - -* end of file -* two newlines (as opposed to the normal one) -* command-terminating token (i.e. all other ways of ending commands work the same as usual, and this does not affect other elements of the PowerShell syntax) - -The pros/cons to this new syntax are as follows: - -**Pros:** - -* allows the scripter to wrap commands how they see fit, while still getting Intellisense and tab completion, without using backticks. -* parameters and arguments are entered the exact same way they would be if they were all placed on one line. -* ad hoc could support this syntax as well (PSReadline could wait for a double-enter when in multi-line command parsing mode) -* no breaking changes (a standalone @ is currently an unrecognized token in PowerShell no matter where it is used). -* users can use a blank line to terminate the command, or they can opt to use a semi-colon or some other valid command-terminating token instead. - -**Cons:** - -* no known cons at this time - -## Motivation - - As a script/module author, - I can wrap commands across multiple lines easily and intuitively without backticks or splatting - so that my scripts remain easy to write and maintain while still giving me the benefits of Intellisense and tab completion. - -## Specification - -* expand the command parser to accept multi-line command parameters/arguments after an at symbol (`@`) is encountered at the end of a line -* terminate multi-line commands when the parser encounters two newlines (rather than one), or when the parser encounters any other normal command-terminating token - -Note: -* for commands that do not use the stop-parsing sigil in their arguments, command-terminating tokens include a pipe symbol, a redirection operator, a closing enclosure, or a semi-colon. -* for commands that do use the stop-parsing sigil in their arguments, command-terminating tokens include a pipe symbol or a redirection operator. - -## Alternate Proposals and Considerations - -### A different sigil - -The original draft of this RFC included different options for the sigil that could be used to enter multi-line parameter/argument parsing mode, and others were presented in the discussion however none of the other sigils that were presented could be used without breaking changes. When considering an alternate sigil, it must be something that can be identified as a unique token without breaking commands that accept multiple strings as positional parameters, such as Write-Host (which can write many sigils to the console) or commands external to PowerShell. - -### Enclosures instead of a sigil - -The original draft also included some proposals for enclosures instead of a leading sigil. While it may seem up front that enclosures make good sense, some thought needs to be given to the stop-parsing sigil, which causes PowerShell to treat closing enclosures as arguments for a command. - -For example, consider this syntax: - -```PowerShell -. {"./plink.exe" @ - --% - $Hostname - -l $Username - -pw $Password - $Command} -``` - -That command will not parse because there is no closing brace for the script block. What appears to be a closing brace is placed after the stop-parsing sigil, and therefore treated as an argument to the plink command. To correct this, the closing brace must be placed on a separate line, but in a multi-line command you cannot do that (because the command is multi-line, so where would the parser terminate after a stop-parsing sigil) and therefore, unless the sigil used to identify the end of the multi-line parameter/arguments was one that could be respected by the stop-parsing sigil, and safely be introduced without risk to breaking changes, enclosures simply cannot be used. - -### Allowing multi-line continuance for more than just commands - -Aside from easier multi-line wrapping parameters/arguments, there are scenarios where it would be useful to have easier multi-line wrapping for other statements as well, and some members of the community have [requested support for these scenarios](https://github.com/PowerShell/PowerShell/issues/9813). PowerShell currently supports line wrapping for objects when the line ends with the dot-reference operator, like this: - -```PowerShell -$string. - ToUpper(). - Trim(). - Length -``` - -Other languages like C#, where an explicit line terminator is used, allow users to wrap such lines with the dot-reference operator at the beginning of a line, which looks something like this: - -```PowerShell -$string - .ToUpper() - .Trim() - .Length -``` - -While the Parser could handle looking ahead for methods with arguments (round brackets), there is a problem with members or with methods with no arguments (which can be invoked in PowerShell to get the method signature(s)), because you can create a function with a name that starts with a dot (e.g. `function .dot {'see?'}; .dot`). - -If we support a single sigil as a general multi-line continuance (not just for command parameters) until a statement terminator or a blank line, then we could support this syntax: - -```PowerShell -$string @ - .ToUpper() - .Trim() - .Length - -``` - -Since there is a blank line, that would just work. If it terminated with a semi-colon, that would work as well. Suddenly multi-line continuance becomes a general feature, more visible than backtick ever was, easier to use than backtick is since `@` is not an escape character, and resulting in cleaner, more elegant code that can be written to match the desired style of the author. - -### Inline splatting - -There has also been some discussion about the idea of inline splatting, using a format like `-@{...}` or `-@(...)`. Inline splatting has also been discussed separately on [RFC0002: Generalized Splatting](https://github.com/PowerShell/PowerShell-RFC/blob/master/2-Draft-Accepted/RFC0002-Generalized-Splatting.md), but using the syntax `@@{...}` or `@@(...)`. Here is an example showing what that might look like: - -```PowerShell -Get-ChildItem -@{ - LiteralPath = $rootFolder - File = $true - Filter = '*.ps*1' -} -``` - -Using inline splatting to be able to span a single command across multiple lines like this has several limitations, including: - -1. You cannot transition to/from the inline splatted syntax without a bunch of manual tweaks to the command (either converting parameter syntax into hashtable or array syntax or vice versa). -2. You're forced to choose between named parameters or positional parameters/arguments for each splatted collection. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two (the example shown just above is also used earlier in this RFC with positional parameters and switch parameters used without values, matching the way it is often used as a single-line command). -3. There's no way to include unparsed arguments after the stop-parsing sigil in splatting. You can add it afterwards, but not include it within. -4. Splatting requires a different syntax than typical parameter/argument input, which is more to learn. In contrast, the proposal above only requires learning about the `@` sigil (borrowed from splatting, but without specifying hashtables or arrays -- just allow all content until a newline), reducing the learning curve and allowing users to use parameters the same way in either case. - -Further, unlike using a leading sigil such as `@`, which would work with Intellisense and tab expansion as they are coded now, inline splatting would require special work to make Intellisense and tab expansion work with it. That's not a reason not to do it, but it is more code to write/maintain. - -### Breaking changes - -All previous options from the original RFC and the discussion about it that would have introduced breaking changes have been removed in favor of a syntax that just works to the specification without any breaking changes, regardless of how you use it. diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance.md b/1-Draft/RFCNNNN-Multi-Line-Continuance.md new file mode 100644 index 00000000..18c9bd7a --- /dev/null +++ b/1-Draft/RFCNNNN-Multi-Line-Continuance.md @@ -0,0 +1,234 @@ +--- +RFC: RFCnnnn +Author: Kirk Munro +Status: Draft +SupercededBy: N/A +Version: 0.2 +Area: Parser/Tokenizer +Comments Due: June 16, 2019 +Plan to implement: Yes +--- + +# Multi-line continuance + +Consider this example of a New-ADUser command invocation: + +```PowerShell +New-ADUser -Name 'Jack Robinson' -GivenName 'Jack' -Surname 'Robinson' -SamAccountName 'J.Robinson' -UserPrincipalName 'J.Robinson@enterprise.com' -Path 'OU=Users,DC=enterprise,DC=com' -AccountPassword (Read-Host -AsSecureString 'Input Password') -Enabled $true +``` + +By itself it's not too much to handle, but in a script commands with many +parameters like this can be difficult to manage. + +To wrap this command across multiple lines, users can either use backticks or +they can use splatting. The former is a syntactical nuisance which should +really only be used in situations when no other option is available. The latter +is helpful, but it puts the parameters before the command, making it more +difficult for less experienced users to learn/use, and all scripters lose the +benefits of tab completion and Intellisense for parameters when they use +splatting. + +As a workaround, they can work out the parameters they want to use for the +command first, and then convert it into a splatted command, but that's onerous. +Even though Visual Studio Code has an extension that makes splatting easier, as +can be seen [here](https://sqldbawithabeard.com/2018/03/11/easily-splatting-powershell-with-vs-code/), once you've converted to splatting you still lose Intellisense +for future updates unless you work from the command first and then add to your +splatted collection, and that's just in Visual Studio Code. Other editors may +or may not support that functionality, and users working in a standalone +terminal won't have that available to them either. + +Instead, why not allow users to wrap commands across multiple lines in a more +intuitive way without having to deal with backticks on every line or splatting, +like this: + +```PowerShell +New-ADUser @ + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + -UserPrincipalName 'J.Robinson@enterprise.com' + -Path 'OU=Users,DC=enterprise,DC=com' + -AccountPassword (Read-Host -AsSecureString 'Input Password') + -Enabled $true + +Get-ChildItem @ + $rootFolder + -File + -Filter '*.ps*1' + +``` + +Of course, they could invoke external commands and pass through arguments this +way as well: + +```PowerShell +& "./plink.exe" @ + --% $Hostname -l $Username -pw $Password $Command + +cacls @ + c:\docs\work + /E /T /C /G + "FinanceUsers":F + +``` + +Further, by generalizing multi-line continuance with a `@` character, we're +allowing users to apply line continuance the way they want to, which opens the +door to more C#-like line wrapping when you're working with multiple members or +methods in .NET, one after another. For example, this would work: + +```PowerShell +$string @ + .ToUpper() + .Trim() + .Length +``` + +In each of these examples, the parser starts parsing the command as a +multi-line command when it encounters the `@` token as the last token on the +line, and in this mode command parsing stops once one of the following is +found: + +* end of file +* two newlines (as opposed to the normal one) +* command-terminating token (i.e. all other ways of ending commands work the +same as usual, and this does not affect other elements of the PowerShell +syntax) + +The pros/cons to this new syntax are as follows: + +**Pros:** + +* allows the scripter to wrap commands how they see fit, while still getting +Intellisense and tab completion, without using backticks. +* aside from the `@` character to initiate multi-line continuance, the rest of +the command is entered the exact same way it would be if it was entered on a +single line. +* ad hoc could support this syntax as well (PSReadline could wait for a +double-enter when in multi-line command parsing mode) +* no breaking changes (a standalone `@` is currently an unrecognized token in +PowerShell no matter where it is used). +* users can use a blank line to terminate the command, or they can opt to use +any valid command-terminating token instead, so it has a proper closing +character. + +**Cons:** + +* no known cons at this time + +## Motivation + + As a script/module author, + I can wrap commands across multiple lines easily and intuitively without backticks or splatting + so that my scripts remain easy to write and maintain while still giving me the benefits of Intellisense and tab completion. + +## Specification + +* expand the command parser to accept multi-line commands after an at symbol +(`@`) is encountered at the end of a line +* terminate multi-line commands when the parser encounters two newlines +(rather than one), or when the parser encounters any other command-terminating +token + +Note: +* for commands that do not use the stop-parsing sigil in their arguments, +command-terminating tokens include a pipe symbol, a redirection operator, a +closing enclosure, a semi-colon, or a `&` background operator. +* for commands that do use the stop-parsing sigil in their arguments, +command-terminating tokens include a pipe symbol or a redirection operator. + +## Alternate Proposals and Considerations + +### A different sigil + +The original draft of this RFC included different options for the sigil that +could be used to enter multi-line parameter/argument parsing mode, and others +were presented in the discussion however none of the other sigils that were +presented could be used without breaking changes. When considering an alternate +sigil, it must be something that can be identified as a unique token without +breaking commands that accept multiple strings as positional parameters, such +as Write-Host (which can write many sigils to the console) or commands external +to PowerShell. + +### Enclosures instead of a sigil + +The original draft also included some proposals for enclosures instead of a +single leading sigil. While it may seem up front that enclosures make good +sense, some thought needs to be given to the stop-parsing sigil, which causes +PowerShell to treat closing enclosures as arguments for a command. + +For example, consider this syntax: + +```PowerShell +. {"./plink.exe" @ + --% + $Hostname + -l $Username + -pw $Password + $Command} +``` + +That command will not parse because there is no closing brace for the script +block. What appears to be a closing brace is placed after the stop-parsing +sigil, and therefore treated as an argument to the plink command. To correct +this, the closing brace must be placed on a separate line, but in a multi-line +command you cannot do that (because the command is multi-line, so where would +the parser terminate after a stop-parsing sigil) and therefore, unless the +sigil used to identify the end of the multi-line parameter/arguments was one +that could be respected by the stop-parsing sigil, and safely be introduced +without risk to breaking changes, enclosures simply cannot be used. + +### Inline splatting + +There has also been some discussion about the idea of inline splatting, using a +format like `-@{...}` or `-@(...)`. Inline splatting has also been discussed +separately on [RFC0002: Generalized Splatting](https://github.com/PowerShell/PowerShell-RFC/blob/master/2-Draft-Accepted/RFC0002-Generalized-Splatting.md), but using the syntax `@@{...}` or +`@@(...)`. + +Here is an example showing what that might look like: + +```PowerShell +Get-ChildItem -@{ + LiteralPath = $rootFolder + File = $true + Filter = '*.ps*1' +} +``` + +Using inline splatting to be able to span a single command across multiple +lines like this has several limitations, including: + +1. You cannot transition to/from the inline splatted syntax without a bunch of +manual tweaks to the command (either converting parameter syntax into hashtable +or array syntax or vice versa). +1. You're forced to choose between named parameters or positional +parameters/arguments for each splatted collection. i.e. You can splat in a +hashtable of named parameter/value pairs or an array of positional values, but +you can't mix the two (the example shown just above is also used earlier in +this RFC with positional parameters and switch parameters used without values, +matching the way it is often used as a single-line command). +1. There's no way to include unparsed arguments after the stop-parsing sigil in +splatting. You can add it afterwards, but not include it within. +1. Splatting requires a different syntax than typical parameter/argument input, +which is more to learn. In contrast, the proposal above only requires learning +about the `@` sigil (borrowed from splatting, but without specifying hashtables +or arrays -- just allow all content until a newline), reducing the learning +curve and allowing users to use parameters the same way in either case. +1. Inline splatting attempts to resolve the issue for commands with arguments, +but it does nothing for other scenarios where you want specific line wrapping +other than the defaults that PowerShell implicitly supports. + +Further, unlike using a leading sigil such as `@`, which would work with +Intellisense and tab expansion as they are coded now, inline splatting would +require special work to make Intellisense and tab expansion work with it. That +is not a reason not to do it, but it is more code to write and maintain. + +### Breaking changes + +None. + +All previous options from the original RFC and the discussion about it that +would have introduced breaking changes have been removed in favor of a syntax +that just works to the specification without any breaking changes, regardless +of how you use it. From 8b57249f4abf1b6a3ebc880b57feb5e4a53db84f Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Wed, 24 Jul 2019 21:31:57 -0300 Subject: [PATCH 18/22] add alternate proposal with enclosures --- 1-Draft/RFCNNNN-Multi-Line-Continuance.md | 107 ++++++++++++++++++---- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance.md b/1-Draft/RFCNNNN-Multi-Line-Continuance.md index 18c9bd7a..e805ae83 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuance.md @@ -3,7 +3,7 @@ RFC: RFCnnnn Author: Kirk Munro Status: Draft SupercededBy: N/A -Version: 0.2 +Version: 0.3 Area: Parser/Tokenizer Comments Due: June 16, 2019 Plan to implement: Yes @@ -115,7 +115,9 @@ character. **Cons:** -* no known cons at this time +* using a blank line as a statement terminator will be hard for some to accept +(if you're one of those folks, read below to the alternative proposals and +considerations section). ## Motivation @@ -153,31 +155,95 @@ to PowerShell. ### Enclosures instead of a sigil -The original draft also included some proposals for enclosures instead of a -single leading sigil. While it may seem up front that enclosures make good -sense, some thought needs to be given to the stop-parsing sigil, which causes -PowerShell to treat closing enclosures as arguments for a command. - -For example, consider this syntax: +Instead of only requiring a single leading sigil, some users prefer the notion +of enclosures such that the multi-line command parsing mode would have a very +clear and well defined start and end. To meet that need, we could follow the +here-string syntax in PowerShell as an example, offering syntax like the +following: ```PowerShell -. {"./plink.exe" @ +. {"./plink.exe" @` --% $Hostname -l $Username -pw $Password - $Command} + $Command +`@} ``` -That command will not parse because there is no closing brace for the script -block. What appears to be a closing brace is placed after the stop-parsing -sigil, and therefore treated as an argument to the plink command. To correct -this, the closing brace must be placed on a separate line, but in a multi-line -command you cannot do that (because the command is multi-line, so where would -the parser terminate after a stop-parsing sigil) and therefore, unless the -sigil used to identify the end of the multi-line parameter/arguments was one -that could be respected by the stop-parsing sigil, and safely be introduced -without risk to breaking changes, enclosures simply cannot be used. +All this would do is prevent newline tokens within the enclosures from being +treated as statement terminators. + +The closing closure could also be a recognized statement terminator even when +used after the stop parsing sigil, allowing those commands to be wrapped across +multiple lines as well. + +Like here-string enclosures, we could require that the opening closure be the +last token on a line. Unlike here-string enclosures, however, it would be +preferable if the closing closure did not have to be at the start of a line, +since there is no need for it to be. It would simply have to be the first token +on line to close the statement, allowing for indentation within scripts. + +This alternative also allows for blank lines to be used within the enclosures, +such that Scenario 3 in @dragonwolf83's comment could be supported and written +like this: + +```PowerShell +New-ADUser @` + -Name 'Jack Robinson' + -GivenName 'Jack' + -Surname 'Robinson' + -SamAccountName 'J.Robinson' + + -UserPrincipalName ( + 'J.Robinson@enterprise.com' + ) + + # Get the list of regions for where a user would reside in to put the user into the correct region + -Path ( + $region = Get-Region -Name 'Jack Robinson' + "OU=Users,OU=$region,DC=enterprise,DC=com" + ) + + -AccountPassword ( + Read-Host -AsSecureString 'Input Password' + ) + + -Enabled $true +`@ + +Get-ChildItem @` + $rootFolder + -File + -Filter '*.ps*1' +`@ +``` + +The best part is that it doesn't appear this syntax would introduce a breaking +change at all. + +If people feel the backtick is still not visible enough here (and therefore not +desirable for this purpose), we should keep the `@` portion of the enclosures +so that we can avoid breaking changes, and simply replace the backtick with +something else. For example, we could do this instead: + +```PowerShell +Get-ChildItem @- + $rootFolder + -File + -Filter '*.ps*1' +-@ +``` + +Backticks offer the advantage of continuing what they represent in PowerShell +already (line continuation), and they are syntactically very similar to here- +strings when used with the `@` symbol. That last point could be seen as a +disadvantage as well, because they may be visually harder to distinguish from +a single-quoted here-string. + +The `@-|-@` alternative doesn't pick up on the backtick for line continuation, +but it is visually unique and easy to see in a script. The `-` character could +be seen as representing the line that makes up the statement as well. ### Inline splatting @@ -226,7 +292,8 @@ is not a reason not to do it, but it is more code to write and maintain. ### Breaking changes -None. +No known breaking changes in the original proposal, nor the alternative version +that uses enclosures. All previous options from the original RFC and the discussion about it that would have introduced breaking changes have been removed in favor of a syntax From a1e4c0e019b02fb8734c0f869258e85dbd42731b Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Wed, 24 Jul 2019 21:38:02 -0300 Subject: [PATCH 19/22] minor update --- 1-Draft/RFCNNNN-Multi-Line-Continuance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance.md b/1-Draft/RFCNNNN-Multi-Line-Continuance.md index e805ae83..50c22aa7 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuance.md @@ -172,7 +172,7 @@ following: ``` All this would do is prevent newline tokens within the enclosures from being -treated as statement terminators. +treated as statement terminators in the current statement. The closing closure could also be a recognized statement terminator even when used after the stop parsing sigil, allowing those commands to be wrapped across From d7f3899abd789ad1fd487185ddf97195f7185806 Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Thu, 25 Jul 2019 16:20:02 -0300 Subject: [PATCH 20/22] replace continuance with continuation --- ...-Continuance.md => RFCNNNN-Multi-Line-Continuation.md} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename 1-Draft/{RFCNNNN-Multi-Line-Continuance.md => RFCNNNN-Multi-Line-Continuation.md} (97%) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuance.md b/1-Draft/RFCNNNN-Multi-Line-Continuation.md similarity index 97% rename from 1-Draft/RFCNNNN-Multi-Line-Continuance.md rename to 1-Draft/RFCNNNN-Multi-Line-Continuation.md index 50c22aa7..5f20d019 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuance.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuation.md @@ -9,7 +9,7 @@ Comments Due: June 16, 2019 Plan to implement: Yes --- -# Multi-line continuance +# Multi-line continuation Consider this example of a New-ADUser command invocation: @@ -73,8 +73,8 @@ cacls @ ``` -Further, by generalizing multi-line continuance with a `@` character, we're -allowing users to apply line continuance the way they want to, which opens the +Further, by generalizing multi-line continuation with a `@` character, we're +allowing users to apply line continuation the way they want to, which opens the door to more C#-like line wrapping when you're working with multiple members or methods in .NET, one after another. For example, this would work: @@ -102,7 +102,7 @@ The pros/cons to this new syntax are as follows: * allows the scripter to wrap commands how they see fit, while still getting Intellisense and tab completion, without using backticks. -* aside from the `@` character to initiate multi-line continuance, the rest of +* aside from the `@` character to initiate multi-line continuation, the rest of the command is entered the exact same way it would be if it was entered on a single line. * ad hoc could support this syntax as well (PSReadline could wait for a From bd5cd890f123e49a7bab4742258645052b66c107 Mon Sep 17 00:00:00 2001 From: Kirk Munro Date: Mon, 9 Dec 2019 20:32:53 -0400 Subject: [PATCH 21/22] update based on feedback from @joeyaiello --- 1-Draft/RFCNNNN-Multi-Line-Continuation.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuation.md b/1-Draft/RFCNNNN-Multi-Line-Continuation.md index 5f20d019..99b3e9f4 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuation.md +++ b/1-Draft/RFCNNNN-Multi-Line-Continuation.md @@ -21,12 +21,12 @@ By itself it's not too much to handle, but in a script commands with many parameters like this can be difficult to manage. To wrap this command across multiple lines, users can either use backticks or -they can use splatting. The former is a syntactical nuisance which should -really only be used in situations when no other option is available. The latter -is helpful, but it puts the parameters before the command, making it more -difficult for less experienced users to learn/use, and all scripters lose the -benefits of tab completion and Intellisense for parameters when they use -splatting. +they can use splatting. The former is something many members of the community +consider to be a syntactical nuisance which should really only be used in +situations when no other option is available. The latter is helpful, but it +puts the parameters before the command, making it more difficult for less +experienced users to learn/use, and all scripters lose the benefits of tab +completion and Intellisense for parameters when they use splatting. As a workaround, they can work out the parameters they want to use for the command first, and then convert it into a splatted command, but that's onerous. @@ -274,8 +274,10 @@ hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two (the example shown just above is also used earlier in this RFC with positional parameters and switch parameters used without values, matching the way it is often used as a single-line command). -1. There's no way to include unparsed arguments after the stop-parsing sigil in -splatting. You can add it afterwards, but not include it within. +1. Inline splatting does not provide any support for wrapping unparsed +arguments after the stop-parsing sigil. In contrast, with this proposal it +would be possible to span commands that use the stop-parsing sigil across +multiple lines. 1. Splatting requires a different syntax than typical parameter/argument input, which is more to learn. In contrast, the proposal above only requires learning about the `@` sigil (borrowed from splatting, but without specifying hashtables From bfb4d7f5a9920de1b8148637ee14cdf631ce136f Mon Sep 17 00:00:00 2001 From: Joey Aiello Date: Tue, 7 Jul 2020 12:59:16 -0700 Subject: [PATCH 22/22] Prepare RFC0060 (multi-line continuation) for rejection --- .../RFC0060-Multi-Line-Continuation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename 1-Draft/RFCNNNN-Multi-Line-Continuation.md => X-Rejected/RFC0060-Multi-Line-Continuation.md (99%) diff --git a/1-Draft/RFCNNNN-Multi-Line-Continuation.md b/X-Rejected/RFC0060-Multi-Line-Continuation.md similarity index 99% rename from 1-Draft/RFCNNNN-Multi-Line-Continuation.md rename to X-Rejected/RFC0060-Multi-Line-Continuation.md index 99b3e9f4..de9db267 100644 --- a/1-Draft/RFCNNNN-Multi-Line-Continuation.md +++ b/X-Rejected/RFC0060-Multi-Line-Continuation.md @@ -1,7 +1,7 @@ --- -RFC: RFCnnnn +RFC: RFC0060 Author: Kirk Munro -Status: Draft +Status: Rejected SupercededBy: N/A Version: 0.3 Area: Parser/Tokenizer