Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ concurrency:
jobs:
checkpoint-validation:
name: Validate engineering checkpoint
if: ${{ contains(fromJSON('["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2"]'), github.ref_name) }}
if: ${{ contains(fromJSON('["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2","v1.3.3"]'), github.ref_name) }}
runs-on: windows-2022
timeout-minutes: 30
steps:
Expand All @@ -35,7 +35,7 @@ jobs:

validate:
name: Validate exact release source
if: ${{ !contains(fromJSON('["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2"]'), github.ref_name) }}
if: ${{ !contains(fromJSON('["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2","v1.3.3"]'), github.ref_name) }}
runs-on: windows-2022
timeout-minutes: 30
steps:
Expand Down Expand Up @@ -82,7 +82,7 @@ jobs:

test-x64:
name: Build and test x64 Release
if: ${{ !contains(fromJSON('["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2"]'), github.ref_name) }}
if: ${{ !contains(fromJSON('["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2","v1.3.3"]'), github.ref_name) }}
needs: validate
runs-on: windows-2022
timeout-minutes: 240
Expand All @@ -102,7 +102,7 @@ jobs:

release:
name: Build, test, attest, and publish EXE and Portable ZIP
if: ${{ !contains(fromJSON('["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2"]'), github.ref_name) }}
if: ${{ !contains(fromJSON('["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2","v1.3.3"]'), github.ref_name) }}
needs:
- validate
- test-x64
Expand Down
70 changes: 70 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,75 @@
# Changelog

## 1.3.3 - 2026-08-12

Engineering checkpoint for the Pane Search roadmap, Phase 3: performance and
edge-case hardening. Like the earlier checkpoints, this version marks merged
development work only: it is not a published release and produces no
downloadable artifacts; GitHub Latest and WinGet keep pointing at the stable
v1.2.0, and v1.3.0-beta3 remains the newest published prerelease.

### Changed

- Live-typing searches are now coalesced per pane. Each executed search scans
the entire scrollback on the UI thread, and previously every keystroke ran
one such scan synchronously. Keystrokes arriving within 50 ms now collapse
into a single trailing search; the leading keystroke still searches
immediately, so a single keypress is as responsive as before. The coalesced
callback reads the search box's state at fire time, so the latest query
always wins and a stale queued query can never overwrite newer results.
Navigation (Enter, Shift+Enter, the arrow buttons) keeps executing
synchronously with the box's current text and therefore can never act on a
stale query. Deleting the query clears highlights, overview markers, and
status immediately, and a pending coalesced search after Esc finds the box
closed and does nothing.
- An open search now converges while output streams continuously. The
existing OutputIdle refresh is debounced (it fires only after 100 ms of
quiet), so sustained output such as `tail -f` starved it and froze the
match counter, highlights, and overview markers indefinitely. While a
search is active, a companion non-debounced throttle now refreshes the
search at most once per 500 ms during sustained output; quiet terminals
keep using the existing OutputIdle path unchanged. The throttle is armed
only from the output handler while a search is active — with search closed
the output path pays one relaxed atomic load and schedules nothing.
- The scrollbar mark bitmap now repaints only when one of its inputs changes
(geometry, mark categories, search state, pip color, or — while generic
marks render — the buffer). Its content is independent of the thumb
position, yet every throttled scroll tick used to re-enumerate the full
occurrence list and all mark rows to repaint an identical bitmap; plain
scrolling with a large result set now skips that work entirely.

### Fixed

- Resizing a pane with an active search no longer creates a stray selection.
The resize invalidation reused the search-close path, which converts the
focused match into a selection (GH#19358); after a reflow those stored
spans describe the pre-reflow buffer, so the resize could select arbitrary
coordinates and skew the recomputed current match. The close path keeps
selecting the focused result; the resize path now only invalidates.
- Switching between the main and alternate screen buffers now drops stored
search highlight spans immediately. They were computed against the other
buffer, and the renderer could paint them at wrong positions for up to one
refresh interval after entering or leaving a full-screen application.
Search itself keeps following the active buffer, recomputing against the
alternate screen while it is engaged and against the main buffer after it
ends.
- Clearing the search now releases the terminal-side highlight span copy
instead of retaining its capacity until the next search; with very high
match counts that memory previously stayed allocated after Esc.

### Added

- Deterministic regression coverage for the hardened edges: buffer mutation
invalidation and post-output count refresh, focused-match anchoring while
matches are appended, scrollback-eviction safety with a tiny history,
reflow invalidation with the no-stray-selection guarantee, alternate-screen
transitions, search-state generation and mid-output arming semantics,
scrollbar repaint-signature contracts, and wide-character span widths
(Traditional and Simplified Chinese, Japanese, Korean, accented Latin, and
emoji). A search-scan smoke benchmark logs per-query scan cost for common,
rare, no-match, regex, and invalid-regex queries without asserting on wall
clock, and scales up locally through `WINTERM_SEARCH_BENCH_LINES`.

## 1.3.2 - 2026-08-12

Engineering checkpoint for the Pane Search roadmap, Phase 2: search UX and
Expand Down
6 changes: 3 additions & 3 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Microsoft、Windows、Windows Terminalのロゴも使用していません。
- `winTerm-<version>-setup-x64.exe` — 現在のユーザー、または全ユーザーへのインストール用;
- `winTerm-<version>-portable-x64.zip` — 展開してそのまま実行する用。

現在のソースバージョンは `1.3.2` で、
現在のソースバージョンは `1.3.3` で、
最新の安定版リリースは `1.2.0` です。公開されている資産の一覧とチェックサムの全体は、
[最新の公式リリース](https://github.com/HelloThisWorld/winTerm/releases/latest)
を参照してください。
Expand Down Expand Up @@ -111,8 +111,8 @@ PowerShell 7と、[ビルド手順(英語)](docs/build.md)に記載された
.\scripts\winterm\build.ps1 -Configuration Release -Platform x64 -IncludeTests
.\scripts\winterm\test.ps1 -Suite Relevant -Configuration Release -Platform x64
.\scripts\winterm\build-unpackaged.ps1 -Configuration Release -Platform x64
.\scripts\winterm\build-installer.ps1 -Version 1.3.2 -Platform x64
.\scripts\winterm\build-portable.ps1 -Version 1.3.2 -Platform x64
.\scripts\winterm\build-installer.ps1 -Version 1.3.3 -Platform x64
.\scripts\winterm\build-portable.ps1 -Version 1.3.3 -Platform x64
```

アンパッケージ形式の生成処理では、統合されたリソースインデックスを作るための
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ application downloads are:
- `winTerm-<version>-setup-x64.exe` — current-user or all-users installation;
- `winTerm-<version>-portable-x64.zip` — extract and run without installation.

The current source version is `1.3.2`;
The current source version is `1.3.3`;
the latest stable release is `1.2.0`. See the
[latest official Release](https://github.com/HelloThisWorld/winTerm/releases/latest)
for the complete published asset list and checksums.
Expand Down Expand Up @@ -106,8 +106,8 @@ Use PowerShell 7 and the Microsoft Terminal toolchain described in
.\scripts\winterm\build.ps1 -Configuration Release -Platform x64 -IncludeTests
.\scripts\winterm\test.ps1 -Suite Relevant -Configuration Release -Platform x64
.\scripts\winterm\build-unpackaged.ps1 -Configuration Release -Platform x64
.\scripts\winterm\build-installer.ps1 -Version 1.3.2 -Platform x64
.\scripts\winterm\build-portable.ps1 -Version 1.3.2 -Platform x64
.\scripts\winterm\build-installer.ps1 -Version 1.3.3 -Platform x64
.\scripts\winterm\build-portable.ps1 -Version 1.3.3 -Platform x64
```

The unpackaged generator uses an unsigned MSIX only as an upstream build
Expand Down
48 changes: 33 additions & 15 deletions docs/current-progress.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ Last updated: 2026-08-12

## Repository state

- Branch: `feature/v1.3.2-pane-search-phase2`, based on `main` at
`8015963ad` (Pane Search Phase 1 checkpoint, pull request #44)
- Branch: `feature/v1.3.3-pane-search-phase3`, based on `main` at
`97ecb7e85` (Pane Search Phase 2 checkpoint, pull request #45)
- Microsoft Terminal upstream revision:
`1cea42d433253d95c4487a3037db48197b5e72f4`
- Application version: `1.3.2`
- Package/file version: `1.3.2.0`
- PowerShell module version: `1.3.2` with no prerelease suffix
- Application version: `1.3.3`
- Package/file version: `1.3.3.0`
- PowerShell module version: `1.3.3` with no prerelease suffix
- Release channel: `stable` (engineering checkpoint; nothing is published)
- Checkpoint tag: `v1.3.2`, listed with the earlier checkpoint tags in the
- Checkpoint tag: `v1.3.3`, listed with the earlier checkpoint tags in the
release workflow so a pushed checkpoint tag runs quick validation only and
can never produce release artifacts
- Current public Latest: `v1.2.0`, the stable Visual Progress release
- Newest published prerelease: `v1.3.0-beta3` on the beta channel
- Supported target: Windows 11 x64

`v1.3.2` is an engineering checkpoint, the second of the Pane Search roadmap
`v1.3.3` is an engineering checkpoint, the third of the Pane Search roadmap
toward v1.4. Like the v1.2.1 through v1.2.4 Command Timeline checkpoints, it
is a source/development version only: no GitHub Release, website slot, or
WinGet update is produced, and `/releases/latest` keeps resolving to v1.2.0.
Expand All @@ -28,9 +28,10 @@ WinGet update is produced, and `/releases/latest` keeps resolving to v1.2.0.

- Phase 1 — active-pane search — complete at `1.3.1`.
- Phase 2 — search UX and scrollbar overview — complete at `1.3.2`.
- Phase 3 — performance investigation and hardening — next, at `1.3.3`.
- Phase 3 — performance and edge-case hardening — complete at `1.3.3`.
- Final integration — `1.4.0-alpha`, promoted to beta only after manual
user validation.
user validation. Starting `1.4.0-alpha` requires a separate instruction;
it is not begun automatically.

Phase 1 made `Ctrl+F` (with the retained `Ctrl+Shift+F` alias) open the
existing Microsoft Terminal search box inside the focused pane only,
Expand All @@ -55,8 +56,25 @@ only through the existing throttled scrollbar update path — no timers, no
polling. Split panes keep fully isolated search state, including their
overview markers.

Deferred to Phase 3: performance work such as debouncing, large-scrollback
optimization, and search-related edge-case hardening.
Phase 3 hardened that experience for real terminal workloads without adding
any new search engine, index, or persistent state. Live typing is coalesced
per pane (50 ms, leading immediate + trailing latest, reading the search
box's state at fire time so the latest query always wins and navigation can
never act on a stale query). An open search now converges during sustained
output: the debounced OutputIdle refresh is complemented by a non-debounced
500 ms cap armed only while a search is active, so `tail -f`-style streams
no longer freeze the counter, highlights, or overview — and search closed
still means zero recurring search work. The scrollbar mark bitmap repaints
only when its inputs change, so plain scrolling with large result sets no
longer re-enumerates occurrences. Edge cases were fixed deterministically:
pane resize no longer converts pre-reflow spans into a stray selection,
main/alt buffer switches drop the other buffer's highlight spans immediately
(search keeps following the active buffer), and closing search releases the
terminal-side span copy. Regression tests cover mutation invalidation,
match-anchor stability during appended output, scrollback eviction, reflow,
alternate-screen transitions, generation/arming semantics, repaint-signature
contracts, wide-character spans (CJK, Korean, accented Latin, emoji), and a
log-only scan benchmark (`WINTERM_SEARCH_BENCH_LINES` scales it locally).

## Command Timeline status

Expand Down Expand Up @@ -171,10 +189,10 @@ through pull request #32:

## Next steps

1. Pane Search Phase 3 (`1.3.3`): performance investigation and hardening.
2. Final integration checkpoint `1.4.0-alpha`, then manual user validation
before any beta promotion.
3. Collect Command Timeline beta feedback; promote a stable `v1.3.0` only
1. Final integration checkpoint `1.4.0-alpha`, then manual user validation
before any beta promotion. This stage requires a separate instruction
from the user; do not begin it automatically.
2. Collect Command Timeline beta feedback; promote a stable `v1.3.0` only
after beta testing, which is the point at which Latest, WinGet, and the
website stable slot move.

Expand Down
4 changes: 2 additions & 2 deletions scripts/winterm/package-shell-assets.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ foreach ($relativePath in $sourceAssets)
}

$version = Get-Content -LiteralPath (Join-Path $repositoryRoot 'shell\shared\version.json') -Raw | ConvertFrom-Json
if ($version.moduleVersion -ne '1.3.2' -or
if ($version.moduleVersion -ne '1.3.3' -or
$version.modulePrerelease -ne '' -or
$version.applicationVersion -ne '1.3.2' -or
$version.applicationVersion -ne '1.3.3' -or
$version.protocolVersion -ne 1)
{
throw 'The winTerm Shell asset version metadata is invalid.'
Expand Down
4 changes: 2 additions & 2 deletions scripts/winterm/test-release-workflow.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ try
"- 'v*'",
'checkpoint-validation:',
'Validate engineering checkpoint',
'["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2"]',
'["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2","v1.3.3"]',
'verify-version.ps1 -RequireTag',
'test.ps1 -Suite Smoke',
'contents: write',
Expand Down Expand Up @@ -63,7 +63,7 @@ try
}
}

$checkpointGuard = 'contains(fromJSON(''["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2"]''), github.ref_name)'
$checkpointGuard = 'contains(fromJSON(''["v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.1","v1.3.2","v1.3.3"]''), github.ref_name)'
if ([regex]::Matches($workflow, [regex]::Escape($checkpointGuard)).Count -ne 4)
{
throw 'Release workflow must guard the checkpoint validation and all three full release jobs.'
Expand Down
40 changes: 20 additions & 20 deletions scripts/winterm/test-visual-progress.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1431,12 +1431,12 @@ try

$version = $source.VersionMetadata | ConvertFrom-Json
$expectedVersionValues = [ordered]@{
applicationVersion = '1.3.2'
packageVersion = '1.3.2.0'
moduleVersion = '1.3.2'
applicationVersion = '1.3.3'
packageVersion = '1.3.3.0'
moduleVersion = '1.3.3'
modulePrerelease = ''
channel = 'stable'
tag = 'v1.3.2'
tag = 'v1.3.3'
workspaceSchemaVersion = 2
dockingModelVersion = 1
shellProtocolVersion = 1
Expand All @@ -1451,39 +1451,39 @@ try
}
}
$shellVersion = $source.ShellVersion | ConvertFrom-Json
if ($shellVersion.applicationVersion -ne '1.3.2' -or $shellVersion.moduleVersion -ne '1.3.2' -or $shellVersion.protocolVersion -ne 1)
if ($shellVersion.applicationVersion -ne '1.3.3' -or $shellVersion.moduleVersion -ne '1.3.3' -or $shellVersion.protocolVersion -ne 1)
{
throw 'Shell version metadata does not match winTerm version 1.3.2 with protocol version 1.'
throw 'Shell version metadata does not match winTerm version 1.3.3 with protocol version 1.'
}
foreach ($surface in @(
@{ Content = $source.ReleaseMetadata; Value = 'ApplicationVersion{ L"1.3.2" }'; Description = 'About release metadata' },
@{ Content = $source.PackageManifest; Value = 'Version="1.3.2.0"'; Description = 'MSIX package manifest' },
@{ Content = $source.HostResource; Value = 'FILEVERSION 1,3,2,0'; Description = 'Terminal host file version' },
@{ Content = $source.HostResource; Value = '"ProductVersion", "1.3.2\0"'; Description = 'Terminal host display version' },
@{ Content = $source.ShimResource; Value = 'FILEVERSION 1,3,2,0'; Description = 'Shim file version' },
@{ Content = $source.ShimResource; Value = '"ProductVersion", "1.3.2\0"'; Description = 'Shim display version' },
@{ Content = $source.ReleaseMetadata; Value = 'ApplicationVersion{ L"1.3.3" }'; Description = 'About release metadata' },
@{ Content = $source.PackageManifest; Value = 'Version="1.3.3.0"'; Description = 'MSIX package manifest' },
@{ Content = $source.HostResource; Value = 'FILEVERSION 1,3,3,0'; Description = 'Terminal host file version' },
@{ Content = $source.HostResource; Value = '"ProductVersion", "1.3.3\0"'; Description = 'Terminal host display version' },
@{ Content = $source.ShimResource; Value = 'FILEVERSION 1,3,3,0'; Description = 'Shim file version' },
@{ Content = $source.ShimResource; Value = '"ProductVersion", "1.3.3\0"'; Description = 'Shim display version' },
@{ Content = $source.CustomProps; Value = '<VersionMajor>1</VersionMajor>'; Description = 'Executable major version' },
@{ Content = $source.CustomProps; Value = '<VersionMinor>3</VersionMinor>'; Description = 'Executable minor version' },
@{ Content = $source.ShellModuleManifest; Value = "ModuleVersion = '1.3.2'"; Description = 'PowerShell module manifest' },
@{ Content = $source.ShellModule; Value = "`$script:WinTermModuleVersion = '1.3.2'"; Description = 'PowerShell module runtime' },
@{ Content = $source.ShellModuleManifest; Value = "ModuleVersion = '1.3.3'"; Description = 'PowerShell module manifest' },
@{ Content = $source.ShellModule; Value = "`$script:WinTermModuleVersion = '1.3.3'"; Description = 'PowerShell module runtime' },
@{ Content = $source.PackageShellAssets; Value = "'shell\shared\version.json'"; Description = 'Canonical shell version metadata packaging' },
@{ Content = $source.WorkspaceSerializer; Value = '"1.3.2"'; Description = 'Workspace application-version fallback' }
@{ Content = $source.WorkspaceSerializer; Value = '"1.3.3"'; Description = 'Workspace application-version fallback' }
))
{
Assert-Contains $surface.Content $surface.Value $surface.Description
}
foreach ($required in @(
"applicationVersion -eq '1.3.2'",
"packageVersion -eq '1.3.2.0'",
"moduleVersion -eq '1.3.2'",
"tag -eq 'v1.3.2'",
"applicationVersion -eq '1.3.3'",
"packageVersion -eq '1.3.3.0'",
"moduleVersion -eq '1.3.3'",
"tag -eq 'v1.3.3'",
"Workspace Schema version remains 2",
"Docking Model version remains 1",
"Shell Protocol version remains 1",
"Theme Schema remains at version 1"
))
{
Assert-Contains $source.VerifyVersion $required 'Authoritative v1.3.2 version validation surface'
Assert-Contains $source.VerifyVersion $required 'Authoritative v1.3.3 version validation surface'
}

$testBinary = Join-Path $root "bin\$Platform\$Configuration\UnitTests_SettingsModel\SettingsModel.Unit.Tests.dll"
Expand Down
2 changes: 1 addition & 1 deletion scripts/winterm/test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ function Test-ShellExperienceFoundations
}

$manifest = Import-PowerShellDataFile -LiteralPath $moduleManifest
if ($manifest.ModuleVersion -ne '1.3.2' -or
if ($manifest.ModuleVersion -ne '1.3.3' -or
$manifest.PrivateData.PSData.Prerelease -ne '' -or
$manifest.PowerShellVersion -ne '5.1')
{
Expand Down
Loading