Skip to content

Commit 58d45d0

Browse files
Implement list scrolling to keep selected item visible
Co-authored-by: HeyItsGilbert <[email protected]>
1 parent da2667a commit 58d45d0

File tree

2 files changed

+199
-86
lines changed

2 files changed

+199
-86
lines changed

PesterExplorer/Private/Get-ListPanel.ps1

Lines changed: 97 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,59 @@
11
function Get-ListPanel {
2-
<#
3-
.SYNOPSIS
4-
Create a list panel for displaying items in a TUI.
5-
6-
.DESCRIPTION
7-
This function generates a list panel that displays items in a TUI (Text User
8-
Interface) using Spectre.Console. It formats the items based on whether they
9-
are selected or not, and handles special cases like parent directories.
10-
11-
.PARAMETER List
12-
An array of strings to display in the list. Each item can be a file path,
13-
a test name, or a special item like '..' for parent directories.
14-
15-
.PARAMETER SelectedItem
16-
The item that is currently selected in the list. This will be highlighted
17-
differently from unselected items.
18-
19-
.EXAMPLE
20-
Get-ListPanel -List @('file1.txt', 'file2.txt', '..') -SelectedItem 'file1.txt'
21-
22-
This example creates a list panel with three items, highlighting 'file1.txt'
23-
as the selected item.
24-
.NOTES
25-
This is meant to be called by the main TUI function: Show-PesterResult
2+
<#
3+
.SYNOPSIS
4+
Create a list panel for displaying items in a TUI.
5+
6+
.DESCRIPTION
7+
This function generates a list panel that displays items in a TUI (Text User
8+
Interface) using Spectre.Console. It formats the items based on whether they
9+
are selected or not, and handles special cases like parent directories.
10+
11+
The function supports viewport management, showing only a subset of items
12+
when the list is longer than the available display height.
13+
14+
.PARAMETER List
15+
An array of strings to display in the list. Each item can be a file path,
16+
a test name, or a special item like '..' for parent directories.
17+
18+
.PARAMETER SelectedItem
19+
The item that is currently selected in the list. This will be highlighted
20+
differently from unselected items.
21+
22+
.PARAMETER SelectedPane
23+
Indicates which pane is currently selected. Affects the border color of the panel.
24+
25+
.PARAMETER ListScrollPosition
26+
The scroll position within the list. Used for viewport management when the list
27+
is longer than the available display height.
28+
29+
.PARAMETER ListHeight
30+
The height of the list display area. When specified and the list is longer,
31+
viewport management is applied to show only visible items.
32+
33+
.EXAMPLE
34+
Get-ListPanel -List @('file1.txt', 'file2.txt', '..') -SelectedItem 'file1.txt'
35+
36+
This example creates a list panel with three items, highlighting 'file1.txt'
37+
as the selected item.
38+
39+
.EXAMPLE
40+
Get-ListPanel -List $longList -SelectedItem 'item5' -ListScrollPosition 2 -ListHeight 10
41+
42+
This example creates a list panel with viewport management, starting from scroll
43+
position 2 and displaying up to 10 items.
44+
45+
.NOTES
46+
This is meant to be called by the main TUI function: Show-PesterResult
2647
#>
27-
[CmdletBinding()]
28-
param (
29-
[array]
30-
$List,
31-
[string]
32-
$SelectedItem,
33-
[string]$SelectedPane = "list"
48+
[CmdletBinding()]
49+
param (
50+
[array]
51+
$List,
52+
[string]
53+
$SelectedItem,
54+
[string]$SelectedPane = "list",
55+
[int]$ListScrollPosition = 0,
56+
[int]$ListHeight = 0
3457
)
3558
$paneColor = if($SelectedPane -ne "list") {
3659
# If the selected pane is not preview, return an empty panel
@@ -86,8 +109,48 @@ function Get-ListPanel {
86109
Format-SpectrePadded -Padding 0
87110
}
88111
}
89-
}
90-
$results |
91-
Format-SpectreRows |
112+
}
113+
114+
# Apply viewport scrolling if list height is specified and list is long
115+
if ($ListHeight -gt 0 -and $List.Count -gt $ListHeight) {
116+
Write-Debug "Applying list viewport scrolling. List count: $($List.Count), Height: $ListHeight, Scroll: $ListScrollPosition"
117+
118+
# Calculate which items to show based on scroll position and height
119+
$visibleResults = @()
120+
121+
# Add scroll indicator if not at top
122+
if ($ListScrollPosition -gt 0) {
123+
$visibleResults += "[grey]...[/]" | Write-SpectreHost -PassThru | Format-SpectrePadded -Padding 0
124+
}
125+
126+
# Calculate available height (subtract 1 if we added scroll indicator)
127+
$availableHeight = $ListHeight
128+
if ($ListScrollPosition -gt 0) {
129+
$availableHeight--
130+
}
131+
132+
# Add items starting from scroll position
133+
$itemsAdded = 0
134+
for ($i = $ListScrollPosition; $i -lt $results.Count -and $itemsAdded -lt $availableHeight; $i++) {
135+
$visibleResults += $results[$i]
136+
$itemsAdded++
137+
}
138+
139+
# Add more indicator if there are more items below
140+
if (($ListScrollPosition + $itemsAdded) -lt $results.Count) {
141+
if ($itemsAdded -eq $availableHeight) {
142+
# Replace last item with more indicator if we're at max height
143+
$visibleResults[-1] = "[grey]...more[/]" | Write-SpectreHost -PassThru | Format-SpectrePadded -Padding 0
144+
} else {
145+
# Add more indicator if there's space
146+
$visibleResults += "[grey]...more[/]" | Write-SpectreHost -PassThru | Format-SpectrePadded -Padding 0
147+
}
148+
}
149+
150+
$results = $visibleResults
151+
}
152+
153+
$results |
154+
Format-SpectreRows |
92155
Format-SpectrePanel -Header "[white]List[/]" -Expand -Color $paneColor
93156
}

PesterExplorer/Public/Show-PesterResult.ps1

Lines changed: 102 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -70,51 +70,97 @@ function Show-PesterResult {
7070
[Spectre.Console.LiveDisplayContext] $Context
7171
)
7272

73-
#region Initial State
74-
$items = Get-ListFromObject -Object $PesterResult
75-
Write-Debug "Items: $($items.Keys -join ', ')"
76-
$list = [array]$items.Keys
77-
$selectedItem = $list[0]
78-
$stack = [System.Collections.Stack]::new()
79-
$object = $PesterResult
80-
$selectedPane = 'list'
81-
$scrollPosition = 0
73+
#region Initial State
74+
$items = Get-ListFromObject -Object $PesterResult
75+
Write-Debug "Items: $($items.Keys -join ', ')"
76+
$list = [array]$items.Keys
77+
$selectedItem = $list[0]
78+
$stack = [System.Collections.Stack]::new()
79+
$object = $PesterResult
80+
$selectedPane = 'list'
81+
$scrollPosition = 0
82+
$listScrollPosition = 0
8283
#endregion Initial State
8384

8485
while ($true) {
85-
# Check the layout sizes
86-
$sizes = $layout | Get-SpectreLayoutSizes
87-
$previewHeight = $sizes["preview"].Height
88-
$previewWidth = $sizes["preview"].Width
89-
Write-Debug "Preview size: $previewWidth x $previewHeight"
86+
# Check the layout sizes
87+
$sizes = $layout | Get-SpectreLayoutSizes
88+
$previewHeight = $sizes["preview"].Height
89+
$previewWidth = $sizes["preview"].Width
90+
$listHeight = $sizes["list"].Height
91+
Write-Debug "Preview size: $previewWidth x $previewHeight"
92+
Write-Debug "List height: $listHeight"
9093

9194
# Handle input
9295
$lastKeyPressed = Get-LastKeyPressed
9396
if ($null -ne $lastKeyPressed) {
94-
#region List Navigation
95-
if($selectedPane -eq 'list') {
96-
if ($lastKeyPressed.Key -in @("j", "DownArrow")) {
97-
$selectedItem = $list[($list.IndexOf($selectedItem) + 1) % $list.Count]
98-
$scrollPosition = 0
99-
} elseif ($lastKeyPressed.Key -in @("k", "UpArrow")) {
100-
$selectedItem = $list[($list.IndexOf($selectedItem) - 1 + $list.Count) % $list.Count]
101-
$scrollPosition = 0
102-
} elseif ($lastKeyPressed.Key -eq "PageDown") {
103-
$currentIndex = $list.IndexOf($selectedItem)
104-
$newIndex = [Math]::Min($currentIndex + 10, $list.Count - 1)
105-
$selectedItem = $list[$newIndex]
106-
$scrollPosition = 0
107-
} elseif ($lastKeyPressed.Key -eq "PageUp") {
108-
$currentIndex = $list.IndexOf($selectedItem)
109-
$newIndex = [Math]::Max($currentIndex - 10, $list.Count - 1)
110-
$selectedItem = $list[$newIndex]
111-
$scrollPosition = 0
112-
} elseif ($lastKeyPressed.Key -eq "Home") {
113-
$selectedItem = $list[0]
114-
$scrollPosition = 0
115-
} elseif ($lastKeyPressed.Key -eq "End") {
116-
$selectedItem = $list[-1]
117-
$scrollPosition = 0
97+
#region List Navigation
98+
if($selectedPane -eq 'list') {
99+
if ($lastKeyPressed.Key -in @("j", "DownArrow")) {
100+
$selectedItem = $list[($list.IndexOf($selectedItem) + 1) % $list.Count]
101+
$scrollPosition = 0
102+
# Update list scroll position to keep selected item visible
103+
$selectedIndex = $list.IndexOf($selectedItem)
104+
if ($listHeight -gt 0 -and $list.Count -gt $listHeight) {
105+
# If selected item is below visible area, scroll down
106+
if ($selectedIndex -ge ($listScrollPosition + $listHeight - 1)) {
107+
$listScrollPosition = $selectedIndex - $listHeight + 2
108+
}
109+
# If selected item is above visible area, scroll up
110+
elseif ($selectedIndex -lt $listScrollPosition) {
111+
$listScrollPosition = $selectedIndex
112+
}
113+
# Ensure scroll position is within bounds
114+
$listScrollPosition = [Math]::Max(0, [Math]::Min($listScrollPosition, $list.Count - $listHeight))
115+
}
116+
} elseif ($lastKeyPressed.Key -in @("k", "UpArrow")) {
117+
$selectedItem = $list[($list.IndexOf($selectedItem) - 1 + $list.Count) % $list.Count]
118+
$scrollPosition = 0
119+
# Update list scroll position to keep selected item visible
120+
$selectedIndex = $list.IndexOf($selectedItem)
121+
if ($listHeight -gt 0 -and $list.Count -gt $listHeight) {
122+
# If selected item is above visible area, scroll up
123+
if ($selectedIndex -lt $listScrollPosition) {
124+
$listScrollPosition = $selectedIndex
125+
}
126+
# If selected item is below visible area, scroll down
127+
elseif ($selectedIndex -ge ($listScrollPosition + $listHeight - 1)) {
128+
$listScrollPosition = $selectedIndex - $listHeight + 2
129+
}
130+
# Ensure scroll position is within bounds
131+
$listScrollPosition = [Math]::Max(0, [Math]::Min($listScrollPosition, $list.Count - $listHeight))
132+
}
133+
} elseif ($lastKeyPressed.Key -eq "PageDown") {
134+
$currentIndex = $list.IndexOf($selectedItem)
135+
$newIndex = [Math]::Min($currentIndex + 10, $list.Count - 1)
136+
$selectedItem = $list[$newIndex]
137+
$scrollPosition = 0
138+
# Update list scroll position to keep selected item visible
139+
if ($listHeight -gt 0 -and $list.Count -gt $listHeight) {
140+
$listScrollPosition = [Math]::Max(0, [Math]::Min($newIndex - [Math]::Floor($listHeight / 2), $list.Count - $listHeight))
141+
}
142+
} elseif ($lastKeyPressed.Key -eq "PageUp") {
143+
$currentIndex = $list.IndexOf($selectedItem)
144+
$newIndex = [Math]::Max($currentIndex - 10, 0)
145+
$selectedItem = $list[$newIndex]
146+
$scrollPosition = 0
147+
# Update list scroll position to keep selected item visible
148+
if ($listHeight -gt 0 -and $list.Count -gt $listHeight) {
149+
$listScrollPosition = [Math]::Max(0, [Math]::Min($newIndex - [Math]::Floor($listHeight / 2), $list.Count - $listHeight))
150+
}
151+
} elseif ($lastKeyPressed.Key -eq "Home") {
152+
$selectedItem = $list[0]
153+
$scrollPosition = 0
154+
$listScrollPosition = 0
155+
} elseif ($lastKeyPressed.Key -eq "End") {
156+
$selectedItem = $list[-1]
157+
$scrollPosition = 0
158+
# Scroll to bottom to show last item
159+
if ($listHeight -gt 0 -and $list.Count -gt $listHeight) {
160+
$listScrollPosition = $list.Count - $listHeight
161+
} else {
162+
$listScrollPosition = 0
163+
}
118164
} elseif ($lastKeyPressed.Key -in @("Tab", "RightArrow", "l")) {
119165
$selectedPane = 'preview'
120166
} elseif ($lastKeyPressed.Key -eq "Enter") {
@@ -130,22 +176,24 @@ function Show-PesterResult {
130176
Write-Debug "Pushing item into stack: $($items.Item($selectedItem).Name)"
131177
$stack.Push($object)
132178
$object = $items.Item($selectedItem)
133-
}
134-
$items = Get-ListFromObject -Object $object
135-
$list = [array]$items.Keys
136-
$selectedItem = $list[0]
137-
$scrollPosition = 0
179+
}
180+
$items = Get-ListFromObject -Object $object
181+
$list = [array]$items.Keys
182+
$selectedItem = $list[0]
183+
$scrollPosition = 0
184+
$listScrollPosition = 0
138185
} elseif ($lastKeyPressed.Key -eq "Escape") {
139186
# Move up via Esc key
140187
if($stack.Count -eq 0) {
141188
# This is the top level. Exit the loop.
142189
return
143190
}
144-
$object = $stack.Pop()
145-
$items = Get-ListFromObject -Object $object
146-
$list = [array]$items.Keys
147-
$selectedItem = $list[0]
148-
$scrollPosition = 0
191+
$object = $stack.Pop()
192+
$items = Get-ListFromObject -Object $object
193+
$list = [array]$items.Keys
194+
$selectedItem = $list[0]
195+
$scrollPosition = 0
196+
$listScrollPosition = 0
149197
}
150198
}
151199
else {
@@ -171,10 +219,12 @@ function Show-PesterResult {
171219

172220
# Generate new data
173221
$titlePanel = Get-TitlePanel -Item $object
174-
$getListPanelSplat = @{
175-
List = $list
176-
SelectedItem = $selectedItem
177-
SelectedPane = $selectedPane
222+
$getListPanelSplat = @{
223+
List = $list
224+
SelectedItem = $selectedItem
225+
SelectedPane = $selectedPane
226+
ListScrollPosition = $listScrollPosition
227+
ListHeight = $listHeight
178228
}
179229
$listPanel = Get-ListPanel @getListPanelSplat
180230

0 commit comments

Comments
 (0)