Skip to content

Commit c450201

Browse files
authored
✨ Add "Open File" Feature (#346)
* ✨ Add Line info in Get-Karma result * ✨ Add params to open current file - Move `-Meditate` to open the current file - Add `-Library` to open the folder. * ♻️ Cleanup extra brace * 📝 Update help files * 🔧 Fix error in Show-Karma * 🔧 Add embedded quotes for default case * 🐛 Check to ensure koan location exists When Get-PSKoan is called with the user scope it needs to check if the folder actually exists. * ♻️ Streamline Show-Karma editor logic * ✅ Update tests - Use temp dir in show-karma test - Restructure tests to avoid duplication
1 parent 657bdea commit c450201

File tree

5 files changed

+234
-69
lines changed

5 files changed

+234
-69
lines changed

PSKoans/Public/Get-Karma.ps1

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
'ModuleOnly' { $GetParams['Module'] = $Module }
3333
{ $Topic } { $GetParams['Topic'] = $Topic }
3434
}
35+
3536
switch ($PSCmdlet.ParameterSetName) {
3637
'ListKoans' {
3738
Get-PSKoan @GetParams
@@ -110,9 +111,10 @@
110111
KoansPassed = $KoansPassed
111112
TotalKoans = $TotalKoans
112113
CurrentTopic = [PSCustomObject]@{
113-
Name = $KoanFile.Topic
114-
Completed = $PesterTests.PassedCount
115-
Total = $PesterTests.TotalCount
114+
Name = $KoanFile.Topic
115+
Completed = $PesterTests.PassedCount
116+
Total = $PesterTests.TotalCount
117+
CurrentLine = ($NextKoanFailed.StackTrace -split '\r?\n')[1] -replace ':.+'
116118
}
117119
Results = $PesterTests.TestResult
118120
RequestedTopic = $Topic

PSKoans/Public/Get-PSKoan.ps1

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@ function Get-PSKoan {
3232
)
3333

3434
$ParentPath = switch ($Scope) {
35-
'User' { Get-PSKoanLocation }
35+
'User' {
36+
$KoanLocation = Get-PSKoanLocation
37+
Write-Verbose "Checking existence of koans folder"
38+
if (-not (Test-Path $KoanLocation)) {
39+
Write-Verbose "Koans folder does not exist. Initiating full reset..."
40+
Update-PSKoan -Confirm:$false
41+
}
42+
43+
$KoanLocation
44+
}
3645
'Module' { Join-Path -Path $script:ModuleRoot -ChildPath 'Koans' }
3746
}
3847

PSKoans/Public/Show-Karma.ps1

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,16 @@ function Show-Karma {
2929
[switch]
3030
$List,
3131

32-
[Parameter(Mandatory, ParameterSetName = 'OpenFolder')]
32+
[Parameter(Mandatory, ParameterSetName = 'OpenFile')]
3333
[Alias('Meditate')]
3434
[switch]
3535
$Contemplate,
3636

37+
[Parameter(Mandatory, ParameterSetName = 'OpenFolder')]
38+
[Alias('OpenFolder')]
39+
[switch]
40+
$Library,
41+
3742
[Parameter()]
3843
[Alias()]
3944
[switch]
@@ -80,6 +85,40 @@ function Show-Karma {
8085
$KoanLocation | Invoke-Item
8186
}
8287
}
88+
'OpenFile' {
89+
try {
90+
$Results = Get-Karma @GetParams
91+
}
92+
catch {
93+
$PSCmdlet.ThrowTerminatingError($_)
94+
}
95+
96+
$Editor = Get-PSKoanSetting -Name Editor
97+
$FilePath = (Get-PSKoan -Topic $Results.CurrentTopic.Name -Scope User).Path
98+
$LineNumber = $Results.CurrentTopic.CurrentLine
99+
100+
$Arguments = switch ($Editor) {
101+
{ $_ -in 'code', 'code-insiders' } {
102+
'--goto'
103+
'"{0}":{1}' -f (Resolve-Path $FilePath), $LineNumber
104+
'--reuse-window'
105+
}
106+
atom {
107+
'"{0}":{1}' -f (Resolve-Path $FilePath), $LineNumber
108+
}
109+
default {
110+
'"{0}"' -f (Resolve-Path $FilePath)
111+
}
112+
}
113+
114+
if ($Editor -and (Get-Command -Name $Editor -ErrorAction SilentlyContinue)) {
115+
Start-Process -FilePath $Editor -ArgumentList $Arguments
116+
}
117+
else {
118+
Invoke-Item -Path $FilePath
119+
}
120+
}
121+
83122
default {
84123
if ($ClearScreen) {
85124
Clear-Host

Tests/Functions/Public/Show-Karma.Tests.ps1

Lines changed: 149 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ if (-not (Get-Module PSKoans)) {
77
#endregion
88

99
Describe 'Show-Karma' {
10+
BeforeAll {
11+
$StartingLocation = Get-PSKoanLocation
12+
Set-PSKoanLocation -Path "$TestDrive/Koans"
13+
14+
Reset-PSKoan -Confirm:$false
15+
}
16+
17+
AfterAll {
18+
Set-PSKoanLocation -Path $StartingLocation
19+
}
1020

1121
InModuleScope 'PSKoans' {
1222

@@ -23,9 +33,10 @@ Describe 'Show-Karma' {
2333
Expectation = 'ExpectedTest'
2434
It = 'TestIt'
2535
CurrentTopic = [PSCustomObject]@{
26-
Name = 'TestTopic"'
27-
Completed = 0
28-
Total = 4
36+
Name = 'TestTopic"'
37+
Completed = 0
38+
Total = 4
39+
CurrentLine = 1
2940
}
3041
}
3142
}
@@ -77,9 +88,10 @@ Describe 'Show-Karma' {
7788
Expectation = 'ExpectedTest'
7889
It = 'TestIt'
7990
CurrentTopic = [PSCustomObject]@{
80-
Name = 'TestTopic"'
81-
Completed = 0
82-
Total = 4
91+
Name = 'TestTopic"'
92+
Completed = 0
93+
Total = 4
94+
CurrentLine = 1
8395
}
8496
}
8597
}
@@ -109,6 +121,9 @@ Describe 'Show-Karma' {
109121
Mock Get-PSKoan -ModuleName 'PSKoans' { }
110122
Mock Update-PSKoan -ModuleName 'PSKoans' { throw 'Prevent recursion' }
111123
Mock Write-Warning
124+
Mock Test-Path { $false }
125+
Mock Invoke-Item
126+
Mock New-Item
112127
}
113128

114129
It 'should attempt to populate koans and then recurse to reassess' {
@@ -126,6 +141,22 @@ Describe 'Show-Karma' {
126141
It 'throws an error if a Topic is specified that matches nothing' {
127142
{ Show-Karma -Topic 'AboutAbsolutelyNothing' } | Should -Throw -ErrorId 'PSKoans.TopicNotFound'
128143
}
144+
145+
It 'should create PSKoans directory with -Library' {
146+
{ Show-Karma -Library } | Should -Throw -ExpectedMessage 'Prevent recursion'
147+
148+
Assert-MockCalled Test-Path -Times 1
149+
Assert-MockCalled Update-PSKoan -Times 1
150+
Assert-MockCalled New-Item -Times 1
151+
}
152+
153+
It 'should create PSKoans directory with -Contemplate' {
154+
{ Show-Karma -Contemplate } | Should -Throw -ExpectedMessage 'Prevent recursion'
155+
156+
Assert-MockCalled Test-Path -Times 1
157+
Assert-MockCalled Update-PSKoan -Times 1
158+
Assert-MockCalled New-Item -Times 1
159+
}
129160
}
130161

131162
Context 'With -ListTopics Parameter' {
@@ -152,9 +183,10 @@ Describe 'Show-Karma' {
152183
Expectation = 'ExpectedTest'
153184
It = 'TestIt'
154185
CurrentTopic = [PSCustomObject]@{
155-
Name = 'TestTopic"'
156-
Completed = 0
157-
Total = 4
186+
Name = 'TestTopic"'
187+
Completed = 0
188+
Total = 4
189+
CurrentLine = 1
158190
}
159191
RequestedTopic = $Topic
160192
}
@@ -186,73 +218,131 @@ Describe 'Show-Karma' {
186218
}
187219
}
188220

189-
Context 'With -Meditate Switch' {
221+
Context 'With -Contemplate Switch' {
222+
BeforeAll {
223+
$TestFile = New-TemporaryFile
190224

191-
Context 'With "code" Set as the Editor' {
192-
BeforeAll {
193-
Mock Get-Command { $true }
194-
Mock Start-Process {
195-
@{ Editor = $FilePath; Path = $ArgumentList }
225+
Mock Invoke-Item { $Path }
226+
Mock Get-Command { $true } -ParameterFilter { $Name -ne "missing_editor" }
227+
Mock Get-Command { $false } -ParameterFilter { $Name -eq "missing_editor" }
228+
Mock Start-Process {
229+
@{ Editor = $FilePath; Arguments = $ArgumentList }
230+
}
231+
Mock Get-Karma -ModuleName 'PSKoans' {
232+
[PSCustomObject]@{
233+
PSTypeName = 'PSKoans.Result'
234+
Meditation = 'TestMeditation'
235+
KoansPassed = 0
236+
TotalKoans = 400
237+
Describe = 'TestDescribe'
238+
Expectation = 'ExpectedTest'
239+
It = 'TestIt'
240+
CurrentTopic = [PSCustomObject]@{
241+
Name = 'TestTopic"'
242+
Completed = 0
243+
Total = 4
244+
CurrentLine = 1
245+
}
196246
}
197-
Set-PSKoanSetting -Name Editor -Value 'code'
198-
199-
$Result = Show-Karma -Contemplate
200247
}
248+
Mock Get-PSKoan {
249+
[PSCustomObject]@{ Path = $TestFile.FullName }
250+
}
251+
}
201252

202-
It 'should start VS Code with Start-Process' {
203-
$Result.Editor | Should -Be 'code'
253+
AfterAll {
254+
$TestFile | Remove-Item
255+
}
204256

205-
Assert-MockCalled Get-Command -Times 1
206-
Assert-MockCalled Start-Process -Times 1
207-
}
257+
It 'invokes VS Code with "code" set as Editor with proper arguments' {
258+
Set-PSKoanSetting -Name Editor -Value 'code'
259+
$Result = Show-Karma -Contemplate
208260

209-
It 'should pass a resolved path' {
210-
# Resolve-Path doesn't like embedded quotes
211-
$Path = $Result.Path -replace '"'
212-
$Path | Should -BeExactly (Resolve-Path -Path $Path).Path
213-
}
261+
$Result.Editor | Should -BeExactly 'code'
262+
$Result.Arguments[0] | Should -BeExactly '--goto'
263+
$Result.Arguments[1] | Should -MatchExactly '"[^"]+":\d+'
264+
$Result.Arguments[2] | Should -BeExactly '--reuse-window'
214265

215-
It 'should enclose the path in quotes' {
216-
$Result.Path | Should -MatchExactly '"[^"]+"'
217-
}
266+
# Resolve-Path doesn't like embedded quotes
267+
$Path = ($Result.Arguments[1] -split '(?<="):')[0] -replace '"'
268+
$Path | Should -BeExactly (Resolve-Path -Path $Path).Path
269+
270+
Assert-MockCalled Get-Command -Times 1
271+
Assert-MockCalled Start-Process -Times 1
218272
}
219273

220-
Context 'With Editor Not Found' {
221-
BeforeAll {
222-
Mock Get-Command { $false }
223-
Mock Invoke-Item
224-
Set-PSKoanSetting -Name Editor -Value "ascsadsa"
225-
}
274+
It 'invokes the set editor with unknown editor chosen' {
275+
Set-PSKoanSetting -Name Editor -Value 'vim'
226276

227-
It 'should not produce output' {
228-
Show-Karma -Meditate | Should -BeNullOrEmpty
229-
}
277+
$Result = Show-Karma -Contemplate
278+
$Result.Editor | Should -BeExactly 'vim'
279+
$Result.Arguments | Should -MatchExactly '"[^"]+"'
230280

231-
It 'should open the koans directory with Invoke-Item' {
232-
Assert-MockCalled Get-Command -Times 1 -ParameterFilter { $Name -eq "ascsadsa" }
233-
Assert-MockCalled Invoke-Item -Times 1
234-
}
281+
# Resolve-Path doesn't like embedded quotes
282+
$Path = $Result.Arguments -replace '"'
283+
$Path | Should -BeExactly (Resolve-Path -Path $Path).Path
284+
285+
Assert-MockCalled Get-Command -Times 1
286+
Assert-MockCalled Start-Process -Times 1
235287
}
236288

237-
Context 'With Nonexistent KoanLocation' {
238-
BeforeAll {
239-
Mock Test-Path { $false }
240-
Mock Update-PSKoan
241-
Mock Get-Command { $false }
242-
Mock Invoke-Item
243-
Mock New-Item
244-
}
289+
It 'opens the file directly when selected editor is unavailable' {
290+
Set-PSKoanSetting -Name Editor -Value "missing_editor"
291+
292+
Show-Karma -Contemplate | Should -BeExactly $TestFile.FullName
245293

246-
It 'should create PSKoans directory' {
247-
Show-Karma -Meditate
294+
Assert-MockCalled Get-Command -Times 1 -ParameterFilter { $Name -eq "missing_editor" }
295+
Assert-MockCalled Invoke-Item -Times 1
296+
}
297+
}
248298

249-
Assert-MockCalled Test-Path -Times 1
250-
Assert-MockCalled Update-PSKoan -Times 1
251-
Assert-MockCalled Get-Command -Times 1
252-
Assert-MockCalled New-Item -Times 1
253-
Assert-MockCalled Invoke-Item -Times 1
299+
Context 'With -Library Switch' {
300+
BeforeAll {
301+
Mock Get-Command { $true } -ParameterFilter { $Name -ne "missing_editor" }
302+
Mock Get-Command { $false } -ParameterFilter { $Name -eq "missing_editor" }
303+
Mock Start-Process {
304+
@{ Editor = $FilePath; Arguments = $ArgumentList }
254305
}
306+
Mock Invoke-Item { $Path }
307+
}
308+
309+
It 'invokes VS Code with "code" set as Editor with proper arguments' {
310+
Set-PSKoanSetting -Name Editor -Value 'code'
311+
$Result = Show-Karma -Library
312+
313+
$Result.Editor | Should -BeExactly 'code'
314+
315+
# Resolve-Path doesn't like embedded quotes
316+
$Path = $Result.Arguments -replace '"'
317+
$Path | Should -BeExactly (Resolve-Path -Path $Path).Path
318+
319+
Assert-MockCalled Get-Command -Times 1
320+
Assert-MockCalled Start-Process -Times 1
321+
}
322+
323+
It 'invokes the set editor with unknown editor chosen' {
324+
Set-PSKoanSetting -Name Editor -Value 'vim'
325+
326+
$Result = Show-Karma -Library
327+
$Result.Editor | Should -BeExactly 'vim'
328+
329+
# Resolve-Path doesn't like embedded quotes
330+
$Path = $Result.Arguments -replace '"'
331+
$Path | Should -BeExactly (Resolve-Path -Path $Path).Path
332+
333+
Assert-MockCalled Get-Command -Times 1
334+
Assert-MockCalled Start-Process -Times 1
335+
}
336+
337+
It 'opens the file directly when selected editor is unavailable' {
338+
Set-PSKoanSetting -Name Editor -Value "missing_editor"
339+
340+
Show-Karma -Library | Should -BeExactly (Get-PSKoanLocation)
341+
342+
Assert-MockCalled Get-Command -Times 1 -ParameterFilter { $Name -eq "missing_editor" }
343+
Assert-MockCalled Invoke-Item -Times 1
255344
}
256345
}
346+
257347
}
258348
}

0 commit comments

Comments
 (0)