Skip to content

Commit 62bcd27

Browse files
committed
main
1 parent 4338986 commit 62bcd27

File tree

6 files changed

+168
-30
lines changed

6 files changed

+168
-30
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Function
2+
3+
## Default Return
4+
5+
Lua function returns `nil` as default.
6+
7+
```lua
8+
print((function() end)() == nil) -- true
9+
```
10+
11+
## Variadic Parameter
12+
13+
Variadic parameter in lua does not have name and default type, it's a special identifier `...` that has to be expanded to a table using `{ ... }`
14+
15+
Such identifier can be used in:
16+
- `{ ... }`: direct expansion
17+
- `{ a, ..., b }`: append extra items around
18+
- `select('#', ...)` and `select(idx, ...)` to get length or pick one item of the args without intermediate expansion
19+
20+
```lua
21+
local function foo(...)
22+
local args = { ... }
23+
print(table.concat(args, ', '))
24+
end
25+
26+
foo('hello', 'world') -- hello, world
27+
```
28+
29+
```lua
30+
Iterate over variadic without expansion
31+
local function foo(...)
32+
for idx = 1, select('#', ...) do
33+
_ = select(idx, ...)
34+
end
35+
end
36+
```
37+
38+
## Multi-Returns
39+
40+
```lua
41+
local function foo()
42+
return 1, 2, 3
43+
end
44+
45+
local a, b, c = foo()
46+
```
47+
48+
## Meta Functions
49+
50+
Mate Functions are global functions registered by lua runtime but commonly used
51+
52+
- `_G.select`: an operator can perform item picking from **arbitrary number of arguments** including `...` or get length of args
53+
```lua
54+
-- get length of args
55+
_ = select('#', 1, 2, 3) -- 3
56+
-- pick second item
57+
_ = select(2, 1, 2, 3) -- 2
58+
```
59+
- `_G.unpack`: equivalent to `table.unpack`

docs/document/Skill/PowerShell/docs/Language/Function.md

Lines changed: 88 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ function Foo {
1111
```
1212

1313
> [!NOTE]
14-
>
1514
> Default type of a parameter is `System.Object`.
1615
1716
## Implicit Parameter
@@ -41,30 +40,30 @@ function Foo {
4140
[string] $Foo,
4241
[string] $Bar
4342
)
44-
43+
4544
Write-Output "$Foo $Bar"
4645
}
4746
4847
Foo -Foo foo -Bar bar
49-
Foo foo bar # it's the same # [!code highlight]
48+
Foo foo bar # it's the same # [!code highlight]
5049
```
5150

5251
Or use a explicit position argument on attribute.
5352

5453
```ps1
5554
function Foo {
5655
param (
57-
[Parameter(Position = 1)] # [!code highlight]
56+
[Parameter(Position = 1)] # [!code highlight]
5857
[string] $Bar
59-
[Parameter(Position = 0)] # [!code highlight]
58+
[Parameter(Position = 0)] # [!code highlight]
6059
[string] $Foo,
6160
)
62-
61+
6362
Write-Output "$Foo $Bar"
6463
}
6564
6665
Foo -Foo foo -Bar bar
67-
Foo foo bar # it's the same # [!code highlight]
66+
Foo foo bar # it's the same # [!code highlight]
6867
```
6968

7069
PowerShell starts counting the position when there's a value belonging to no explicit parameter name.
@@ -122,7 +121,7 @@ function Foo {
122121
```
123122

124123
> [!NOTE]
125-
> For overriding default parameter outside the function, see [$PSDefaultParameterValues](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters_default_values?view=powershell-7.4#long-description)
124+
> For overriding default parameter outside the function, see [$PSDefaultParameterValues](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters_default_values?view=powershell-7.4#long-description)
126125
127126
## Required Parameter
128127

@@ -139,7 +138,7 @@ param (
139138
> You can omit assignment for boolean attribute parameter.
140139
>```ps1
141140
>param (
142-
> [Parameter(Mandatory)] # Mandatory is true now # [!code highlight]
141+
> [Parameter(Mandatory)] # Mandatory is true now # [!code highlight]
143142
> [string]$RequiredName
144143
>)
145144
>```
@@ -151,16 +150,16 @@ Parameters can have aliases. It's not needed for most of time though since pwsh
151150
```ps1
152151
function Person {
153152
param (
154-
[Alias('n')] # [!code highlight]
153+
[Alias('n')] # [!code highlight]
155154
[string]$Name,
156155
157-
[Alias('a', 'yearsold')] # can have multiple aliases! # [!code highlight]
156+
[Alias('a', 'yearsold')] # can have multiple aliases! # [!code highlight]
158157
[int]$Age
159158
)
160159
Write-Host "Name: $Name, Age: $Age"
161160
}
162161
163-
Person -n "Alice" -a 30 # [!code highlight]
162+
Person -n "Alice" -a 30 # [!code highlight]
164163
```
165164
166165
## Parameter Validation
@@ -204,6 +203,68 @@ param (
204203
)
205204
```
206205
206+
## Parameter Auto-Conversion
207+
208+
For flexibility, PowerShell has no strict type checking on parameter, but it handles implicit conversion on arguments.
209+
Any argument cannot be converted to the target type specified would cease the execution.
210+
211+
Such auto-conversion is quite exhaustive:
212+
213+
- string evaluation by `ToString`
214+
```ps1
215+
& { param([string]$foo) $foo.GetType().Name } -foo 123 # String
216+
```
217+
- number parsing from string such as `[int]::Parse`
218+
```ps1
219+
& { param([int]$foo) $foo.GetType().Name } -foo "123" # Int32
220+
```
221+
- boolean conversion from integer(positive is true, 0 is false)
222+
```ps1
223+
& { param([boolean]$foo) $foo } -foo 0 # False
224+
& { param([boolean]$foo) $foo } -foo 123 # True
225+
```
226+
- argument passed to constructor
227+
```ps1
228+
# directly passed to ctor since argument type matched with parameter type of ctor
229+
& { param([System.IO.FileInfo]$foo) $foo.FullName } -foo "foo" # ~/foo
230+
# eval 123 to string on ctor
231+
& { param([System.IO.FileInfo]$foo) $foo.FullName } -foo 123 # ~/123
232+
```
233+
234+
## Bounded Parameters
235+
236+
Parameters having **manually** specified value would be recorded into an dictionary `$PSBoundParameters`.
237+
Such key-value pairs only stores **initially specified** value of those parameters.
238+
239+
## Closure & Currying
240+
241+
Closure in PowerShell requires a `[scriptblock]` with `GetNewClosure` being called, you can't play it directly with a normal function.
242+
243+
As [documentation](https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.scriptblock.getnewclosure?view=powershellsdk-7.4.0) described:
244+
> `GetNewClosure` returns a new scriptblock bound to a module. **Any local variables in the callers context will be copied into the module**.
245+
246+
```ps1
247+
$bar = 123;
248+
$closure = {
249+
param ($foo)
250+
$bar + $foo
251+
}.GetNewClosure()
252+
253+
& $closure 1 # 124
254+
```
255+
256+
Now we've understand how closure work, we could implement a simple currying like so:
257+
258+
```ps1
259+
function Currying {
260+
param ($prev)
261+
{ param($final) $prev + $final }.GetNewClosure()
262+
}
263+
264+
$currying = Currying -prev 1
265+
$result = & $currying -final 2 # 3
266+
```
267+
207268
## Pass By Reference
208269

209270
Parameter passed by reference is implemented by a wrapper `System.Management.Automation.PSReference`.
@@ -212,14 +273,14 @@ Casting to `[ref]` generates a new wrapper containing the value.
212273

213274
```ps1
214275
function Foo {
215-
param ([ref][int]$foo) # [!code highlight]
276+
param ([ref][int]$foo) # [!code highlight]
216277
$foo.Value = 250
217278
$foo.Value
218279
}
219280
220281
$bar = 1
221282
Foo ([ref]$bar)
222-
$bar # 250 # [!code highlight]
283+
$bar # 250 # [!code highlight]
223284
```
224285

225286
> [!NOTE]
@@ -231,9 +292,9 @@ In a simple function where there's only one series of parameters being taken, we
231292
But things will explode when we're dealing with a pipeline input which might bring multiple objects.
232293

233294
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.
234-
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.
295+
So named blocks are essentially to defined a shared process logic for each object in the pipeline input, and other logic like initialization and finalization.
235296

236-
- `begin`: state initializationa for the pipeline iteration.
297+
- `begin`: state initialization for the pipeline iteration.
237298
- `process`: logic for each pipeline iteration.
238299
- `end`: final action for the completed pipeline iteration.
239300
- `clean`: a `finally` block to execute clean up no matter what happens.(PowerShell 7.3+)
@@ -255,7 +316,7 @@ function Foo {
255316
> echo hello
256317
> }
257318
>}
258-
># equivalent to
319+
># equivalent to
259320
>function Foo {
260321
> echo hello
261322
>}
@@ -286,7 +347,7 @@ A function would generally not acting a cmdlet unless it was annotated with `Cmd
286347
`CmdletBinding()` can have the following properties:
287348

288349
- `DefaultParameterSetName`: pwsh will prefer this name when there's a ambiguity between syntax provided.
289-
- `HelpURI`: link to documenetation
350+
- `HelpURI`: link to documentation
290351
- `SupportsPaging`: implicitly adds parameters `-First`, `-Skip`, `-IncludeTotalCount`, value accessible by `$PSCmdlet.PagingParameters`
291352
```ps1
292353
function foo {
@@ -299,14 +360,14 @@ A function would generally not acting a cmdlet unless it was annotated with `Cmd
299360
```
300361
- `SupportsShouldProcess`: implicitly adds `-Confirm` and `-WhatIf`
301362
- `ConfirmImpact`: specify impact of `-Confirm`
302-
- `PositionalBinding`:
363+
- `PositionalBinding`:
303364
304365
<!-- TODO: complete description for ConfirmImpact and PositionalBinding -->
305366
306367
## Parameter Set
307368
308369
How a same cmdlet manage different syntax for different usages? The trick is **Parameter Set**.
309-
Parameter Set is a classification on paramater to distinguish or limit the use of parameters from scenarios.
370+
Parameter Set is a classification on parameter to distinguish or limit the use of parameters from scenarios.
310371
311372
- a parameter set must have at least one unique parameter to others to identify the set
312373
- a parameter can be member of multiple parameter sets.
@@ -315,7 +376,7 @@ Parameter Set is a classification on paramater to distinguish or limit the use o
315376
- at least one parameter in the Parameter Set is mandatory
316377
- only one parameter in set can accept `ValueFromPipeline`
317378
318-
### Parameter Set Idetifier at Runtime
379+
### Parameter Set Identifier at Runtime
319380
320381
`$PSCmdlet.ParameterSetName` reflects the Parameter Set been chosen when a cmdlet is executing with certain syntax.
321382
@@ -339,7 +400,7 @@ Any function or cmdlet applied with `CmdletBinding()` or `Parameter()` attribute
339400
- WarningVariable (wv): similar to `ev`
340401
- ProgressAction (proga)
341402
- OutVariable (ov): declare **inline** and store the output to the variable. Similar to `ev`.
342-
It's interesting that `-OutVariable` collects incremnentally.
403+
It's interesting that `-OutVariable` collects incrementally.
343404
It collects new item from pipeline on each iteration.
344405
```ps1
345406
1..5 | % { $_ } -OutVariable foo | % { "I am $foo" }
@@ -359,7 +420,7 @@ Any function or cmdlet applied with `CmdletBinding()` or `Parameter()` attribute
359420
360421
Mitigation parameters were added when `CmdletBinding(SupportsShouldProcess)` was applied.
361422
362-
- WhatIf (wi): shows explaination for the command without executing it.
423+
- WhatIf (wi): shows explanation for the command without executing it.
363424
- Confirm (cf): ask for confirmation when executing the command.
364425
365426
## Return
@@ -373,7 +434,7 @@ PowerShell allows implicit return, and multiple implicit returns.
373434
```ps1
374435
function Sum {
375436
param([int]$l, [int]$r)
376-
$l + $r # implicit return # [!code highlight]
437+
$l + $r # implicit return # [!code highlight]
377438
}
378439
379440
# You won't need to declare an array and append it on each loop!
@@ -384,16 +445,16 @@ function Foo {
384445
}
385446
}
386447
387-
(Foo).GetType().Name # object[] # [!code highlight]
448+
(Foo).GetType().Name # object[] # [!code highlight]
388449
```
389450

390451
Explicit return is surely supported, but more like a necessity to exit inside a flow.
391452

392453
```ps1
393454
function Sum {
394455
param([int]$l, [int]$r)
395-
return $l + $r # explicit return # [!code highlight]
396-
$r + $l # not reachable # [!code warning]
456+
return $l + $r # explicit return # [!code highlight]
457+
$r + $l # not reachable # [!code warning]
397458
}
398459
```
399460

docs/document/Skill/PowerShell/docs/Language/Script Block.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ $script = [scriptblock]::Create('echo hello')
2323
& $script # hello
2424
```
2525

26-
## Invoke a Script Block
26+
> [!IMPORTANT]
27+
> scriptblock created in literal `{}` is always aware of current caller context(SessionState) while `[scriptblock]::Create` returns a **unbound scriptblock** which only reads the SessionState from where it was called.
28+
> See [this post](https://mdgrs.hashnode.dev/scriptblock-and-sessionstate-in-powershell)
29+
30+
## Invoke Script Block
2731

2832
```ps1
2933
& { 1, 2 }

docs/document/Skill/PowerShell/docs/Language/String.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,3 +305,12 @@ $OFS = ', '
305305

306306
> [!NOTE]
307307
> `$OFS` is not a builtin variable, you'll have to create it manually or pwsh uses space ` ` as the default separator.
308+
309+
### Parameter
310+
311+
Any value passed to parameter marked as `[string]` would be evaluated using `ToString()`
312+
313+
```ps1
314+
$foo = New-TemporaryFile # type: FileInfo
315+
ri -Path $foo # -Path is [string], $foo would be eval to string using ToString
316+
```

docs/document/Skill/PowerShell/docs/Terminology.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Powershell has its own terminologies besides other shells like bash.
44
It's a shell integrated with .NET, it's not a independent platform.
55

6-
- `cmdlet`: precompiled .NET assemblies work for PowerShell, implemented using other languages typically in `C#`.
6+
- `cmdlet`: pre-compiled .NET assemblies work for PowerShell, implemented using other languages typically in `C#`.
77
- `function`: a command implemented using powershell language itself.
88
- `application`: external executable.
99

@@ -13,6 +13,12 @@ Session is an environment state created on Powershell instance starts.
1313
A session is not a scope, all environment of sessions are isolated.
1414
The scope of the session is the top scope.
1515

16+
### SessionState
17+
18+
A SessionState object holds the state of a PowerShell session or a module.
19+
Most importantly, the SessionState manages variables, functions and cmdlets by holding a stack of Scopes.
20+
**`[scriptblock]` uses the SessionState object to look for variables and functions based on the scoping rule**.
21+
1622
## Runspace
1723

1824
Runspace is a customized instance of Powershell by powershell code.

docs/services/DocumentService.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import fg from 'fast-glob';
33
import Enumerable from 'linq';
44
import * as FileSystem from '../shared/FileSystem';
55
import type { IDocumentService } from './IDocumentService';
6-
import InstallLuaMd from '../document/Skill/NeoVim ColorScheme Development/docs/1. Prerequisite/1. Install lua.md';
76

87
export type DocumentInfo = Record<string, { icon: string; description: string }>;
98

0 commit comments

Comments
 (0)