diff --git a/docs/document/Powershell/docs/Alias.md b/docs/document/Powershell/docs/Alias.md index 3f3608fc..f73c92db 100644 --- a/docs/document/Powershell/docs/Alias.md +++ b/docs/document/Powershell/docs/Alias.md @@ -15,7 +15,13 @@ New-Alias ## Override an Alias ```ps1 -Set-Alias +Set-Alias vim 'nvim --clean -c "source ~/.vimrc"' +``` + +Or use `Set-Item` to manipulate the alias provider directly: + +```ps1 +si alias:vim 'nvim --clean -c "source ~/.vimrc"' ``` > [!TIP] diff --git a/docs/document/Powershell/docs/File System/5.Write to File.md b/docs/document/Powershell/docs/File System/5.Write to File.md index c6e17f65..66ad7d9e 100644 --- a/docs/document/Powershell/docs/File System/5.Write to File.md +++ b/docs/document/Powershell/docs/File System/5.Write to File.md @@ -11,3 +11,11 @@ ls > foo.txt # equivalent to ls | Out-File foo.txt ``` + +## Write Binary Data from External Command + +PowerShell 7.4 added a experimental feature called `PSNativeCommandPreserveBytePipe` to work with external cli that pipes binary stream. + +```ps1 +curl -s -L 'I am a url' > haha.tar.gz +``` diff --git a/docs/document/Powershell/docs/Language/Array.md b/docs/document/Powershell/docs/Language/Array.md index 8fe16175..e647b708 100644 --- a/docs/document/Powershell/docs/Language/Array.md +++ b/docs/document/Powershell/docs/Language/Array.md @@ -53,7 +53,12 @@ So it can be another way to spread out arrays into one. ## Access an Item -Powershell allows +Powershell allows indexer syntax to access one or more items at a time. + +```ps1 +@(1,2,3)[0] # 1 +@(1,2,3)[0, 2] # 1, 3 +``` ## Concatenation diff --git a/docs/document/Powershell/docs/Language/Control Flow.md b/docs/document/Powershell/docs/Language/Control Flow.md index 9ca660a9..343f4ef7 100644 --- a/docs/document/Powershell/docs/Language/Control Flow.md +++ b/docs/document/Powershell/docs/Language/Control Flow.md @@ -16,6 +16,49 @@ ## Newline Indicator +Use `` ` `` to indicate a new line if you do want to finish a long command invocation across multiple lines. + +```ps1 +gci ` +-File ` +-Filter '*.mp4' +``` + +> [!warning] +> **A space is required before the backtick.** +> **And no any chacracter is allowed after the backtick.** + +> [!TIP] +> Stop using backticks! They're ugly! Use hashtable splatting instead. +>```ps1 +>$table = { +> Filter = '*.mp4'; +> File = $true +>} +>gci -file @table +>``` + +## Multi-Line Piping + +### Trailing Piper + +In multiple piping, we can use trailing `|` to indicate the new line, PowerShell regconizes these lines as a whole command piping. + +```ps1 +gps | + foreach CPU | + sort -desc +``` + +### Leading Piper + +Starting with PowerShell 7, `|` is allowed as the first non-space chacracter in a new line. + +```ps1 +gps | foreach CPU + | sort -desc # [!code highlight] +``` + ## Command Chaining ### Multi-Command in Single Line @@ -30,3 +73,24 @@ cd ..; gci -rec -file; echo hello ### Chaining And & Or In PowerShell 7, `&&` and `||` were introduced to do the same command chaining as bash does. + + +## Pattern Matching + +Switch statement behaves similarly when the input is a singular object but can enumerate when the input is a collection. +It has a few different patterns available: + +- Constant: matching by primitive literal. +- Type: matching by target type with `-is` operator. +- Regex: matching by regex string, specifically for `string`. +- Wildcard: matching by wildcard string, specifically for `string`. + +### Constant Pattern + +### Type Pattern + +### Regex Pattern + +### Wildcard Pattern + + diff --git a/docs/document/Powershell/docs/Language/Function.md b/docs/document/Powershell/docs/Language/Function.md index 169328df..189caa9c 100644 --- a/docs/document/Powershell/docs/Language/Function.md +++ b/docs/document/Powershell/docs/Language/Function.md @@ -51,6 +51,20 @@ function Foo { > > Default type of a parameter is `System.Object`. +### Implicit Parameter + +If no parameter name was set, all value passed in will be captured by `$args`, an `object[]`. + +The following example makes an alias for Neovim to mimic the original Vim cli. + +```ps1 +function vim { + nvim --clean -c 'source ~/.vimrc' @args +} + +vim ./foo.txt +``` + ### Positional Parameter Positional parameters allows passing values with explicit names. @@ -69,6 +83,24 @@ Foo -Foo foo -Bar bar Foo foo bar # it's the same # [!code highlight] ``` +Or use a explicit position argument on attribute. + +```ps1 +function Foo { + param ( + [Parameter(Position=1)] # [!code highlight] + [string] $Bar + [Parameter(Position=0)] # [!code highlight] + [string] $Foo, + ) + + Write-Output "$Foo $Bar" +} + +Foo -Foo foo -Bar bar +Foo foo bar # it's the same # [!code highlight] +``` + ### Default Parameter ```ps1 @@ -97,6 +129,12 @@ function Foo { Foo -Foo -Bar $true # [!code highlight] ``` +Manual assignment is also available: + +```ps1 +Foo -f:$false -b $true +``` + ### Required Parameter All parameters are optional by default. Use `[Parameter(Mandatory=$true)]` to mark it as required. @@ -108,6 +146,15 @@ param ( ) ``` +> [!NOTE] +> You can omit assignment for boolean attribute parameter. +>```ps1 +>param ( +> [Parameter(Mandatory)] # Mandatory is true now # [!code highlight] +> [string]$RequiredName +>) +>``` + ### Parameter Alias Parameters can have aliases. It's not needed for most of time though since pwsh can distinguish option by leading string. @@ -115,10 +162,10 @@ Parameters can have aliases. It's not needed for most of time though since pwsh ```ps1 function Person { param ( - [Alias("n")] # [!code highlight] + [Alias('n')] # [!code highlight] [string]$Name, - [Alias("a")] # [!code highlight] + [Alias('a', 'yearsold')] # can have multiple aliases! # [!code highlight] [int]$Age ) Write-Host "Name: $Name, Age: $Age" @@ -127,6 +174,39 @@ function Person { Person -n "Alice" -a 30 # [!code highlight] ``` +### Parameter Validation + +Pass a validation logic as script block to `ValidateScript` attribute, `$_` represents singular value of the parameter or current item of a collection. +Will throw an error if any parameter does not satisfies the condition. + +```ps1 +param ( + [ValidateScript({ ($_ % 2) -ne 0 })] + [int[]]$Odd + [ValidateScript({ $_.Length < 5 })] + [string]$Name +) +``` + +## Named Blocks + +In a simple function where there's only one series of parameters being taken, we don't have to use any complex logic. +But things will explode when we're dealing with a pipeline input which might bring multiple objects. + +The pipeline mechanism is essentially based on the `Enumerator` so if we collect all items into a new collection as parameter value, it can be a huge performance issue. +So named blocks are essentially to defined a shared process logic for each object in the pipeline input, and other logic like initializationa and finalization. + +> [!NOTE] +> When no named block were specified, `end` block is used to represent the whole logic of a simple function. + +```ps1 +function Foo { + begin {} + process {} + end {} +} +``` + ## Lifetime - Function should be define before it was called. diff --git a/docs/document/Powershell/docs/Understanding Pipeline.md b/docs/document/Powershell/docs/Understanding Pipeline.md index 03b1a19b..c51259b2 100644 --- a/docs/document/Powershell/docs/Understanding Pipeline.md +++ b/docs/document/Powershell/docs/Understanding Pipeline.md @@ -9,23 +9,48 @@ Overview of pipeline in powershell: ## Pipeline Parameter Binding -## How Cmdlet Accept a Pipeline Input +## How Cmdlet Accept Pipeline Input There's two solution when a pipeline input comes in as a fallback: -- ByValue: accepts when the coming object can be cast to the target type of the parameter. +- ByValue: the default strategy. Accepts when the coming object can be cast or converted to the target type of the parameter. - ByPropertyName: accepts when the coming object has property name matched to any parameter name of the cmdlet. +### By Value + + + +### By PropertyName ```ps1 spps -Name (gci -File | foreach Name) -# is equivalent to +# is equivalent to the following # because FileInfo has Name which matches to -Name parameter of spps cmdlet gci -File | spps ``` + > [!WARNING] > If multiple matches exist on ByPropertyName solution, powershell throws an error since these paramters might not be allowed to be used together. -By value is always tried first, and then use ByPropertyName, or it finally throws. +ByValue is always tried first, and then use ByPropertyName, or it finally throws. A parameter accepts pipeline input does not necessarily have both solutions, it can have at least one of them. + +## How PowerShell Enumerate Pipeline Input + +As we know, PowerShell can handle multiple objects from an enumerator from object that implements `IEnumerable` or `IEnumerable`, or even duck typed with `GetEnumerator`. + +While for types that are not linear collection, manually invoking `GetEnumerator` is required when being passed as pipeline input. + +- `IDictionary<,>` and `IDictionary` +- HashTable has dynamic typing so we can't presume a uniformed calculation for our cmdlet +- `string` is `IEnumerable` but we surely don't expect the auto enumeration. + +```ps1 +$table = @{ Name = 'foo'; Age = 18 } +($table | measure).Count # 1 +($table.GetEnumerator() | measure).Count # 2 # [!code highlight] +``` + +This is simply because these types are more likely to be treated as a whole object, even when dictionaries are `IEnumerable>`. + diff --git a/docs/services/ISidebarService.ts b/docs/services/ISidebarService.ts index b43f150a..4256654e 100644 --- a/docs/services/ISidebarService.ts +++ b/docs/services/ISidebarService.ts @@ -8,6 +8,6 @@ export interface ISidebarService { getSidebarOfDocument(name: DocumentName): DefaultTheme.SidebarItem[]; transformFolderToSidebarItem( folder: File.DirectoryInfo, - baseLink: string + baseLink: string, ): DefaultTheme.SidebarItem[]; }