Skip to content

Commit 6487646

Browse files
author
Justin Chung
committed
Merge remote-tracking branch 'upstream/master' into sqliteHistory
2 parents 3a7a604 + e563a2f commit 6487646

40 files changed

+813
-722
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"-NoProfile",
1515
"-NoExit",
1616
"-Command",
17-
"Import-Module '${workspaceFolder}/PSReadLine/bin/Debug/netstandard2.0/win-x64/PSReadLine.psd1'"
17+
"Import-Module '${workspaceFolder}/PSReadLine/bin/Debug/net8.0/PSReadLine.psd1'"
1818
],
1919
"console": "integratedTerminal",
2020
"justMyCode": false,

.vscode/tasks.json

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"version": "2.0.0",
3-
"tasks": [
2+
"version": "2.0.0",
3+
"tasks": [
44
{
55
"label": "Bootstrap",
66
"type": "shell",
@@ -17,9 +17,7 @@
1717
"type": "shell",
1818
"command": "pwsh",
1919
"args": [
20-
"./build.ps1",
21-
"-Configuration",
22-
"${input:configuration}"
20+
"./build.ps1"
2321
],
2422
"group": {
2523
"kind": "build",
@@ -37,8 +35,6 @@
3735
"args": [
3836
"./build.ps1",
3937
"-Test",
40-
"-Configuration",
41-
"${input:configuration}",
4238
"-Framework",
4339
"${input:framework}"
4440
],
@@ -51,7 +47,7 @@
5147
"panel": "dedicated",
5248
"clear": true
5349
},
54-
"detail": "Run unit tests with selected configuration and framework"
50+
"detail": "Run unit tests with selected framework"
5551
},
5652
{
5753
"label": "Clean",
@@ -66,16 +62,6 @@
6662
}
6763
],
6864
"inputs": [
69-
{
70-
"id": "configuration",
71-
"description": "Build Configuration",
72-
"type": "pickString",
73-
"options": [
74-
"Debug",
75-
"Release"
76-
],
77-
"default": "Debug"
78-
},
7965
{
8066
"id": "framework",
8167
"description": "Target Framework",

MockPSConsole/MockPSConsole.csproj

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,14 @@
44
<OutputType>Exe</OutputType>
55
<RootNamespace>MockPSConsole</RootNamespace>
66
<AssemblyName>MockPSConsole</AssemblyName>
7-
<TargetFrameworks>net472;net6.0</TargetFrameworks>
7+
<TargetFramework>net8.0</TargetFramework>
88
<FileAlignment>512</FileAlignment>
99
<ApplicationManifest>Program.manifest</ApplicationManifest>
1010
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
1111
</PropertyGroup>
1212

13-
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
14-
<PackageReference Include="PowerShellStandard.Library" version="5.1.0" />
15-
</ItemGroup>
16-
17-
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
18-
<PackageReference Include="Microsoft.PowerShell.SDK" version="7.2.24" />
13+
<ItemGroup>
14+
<PackageReference Include="Microsoft.PowerShell.SDK" version="7.4.13" />
1915
</ItemGroup>
2016

2117
<ItemGroup>

PSReadLine.build.ps1

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,37 @@ param(
1919
[ValidateSet("Debug", "Release")]
2020
[string]$Configuration = (property Configuration Release),
2121

22-
[ValidateSet("net472", "net6.0")]
23-
[string]$TestFramework,
24-
2522
[switch]$CheckHelpContent
2623
)
2724

2825
Import-Module "$PSScriptRoot/tools/helper.psm1"
2926

30-
# Final bits to release go here
31-
$targetDir = "bin/$Configuration/PSReadLine"
27+
# Dynamically read target framework from project file
28+
$csprojPath = "$PSScriptRoot/PSReadLine/PSReadLine.csproj"
29+
[xml]$csproj = Get-Content $csprojPath
30+
$targetFramework = $csproj.Project.PropertyGroup.TargetFramework | Where-Object { $_ } | Select-Object -First 1
3231

33-
if (-not $TestFramework) {
34-
$TestFramework = $IsWindows ? "net472" : "net6.0"
32+
if (-not $targetFramework) {
33+
throw "Could not determine TargetFramework from $csprojPath"
3534
}
3635

36+
Write-Verbose "Target framework: $targetFramework"
37+
38+
# Final bits to release go here
39+
$targetDir = "bin/$Configuration/PSReadLine"
40+
3741
function ConvertTo-CRLF([string] $text) {
3842
$text.Replace("`r`n","`n").Replace("`n","`r`n")
3943
}
4044

41-
$polyFillerParams = @{
42-
Inputs = { Get-ChildItem Polyfill/*.cs, Polyfill/Polyfill.csproj }
43-
Outputs = "Polyfill/bin/$Configuration/netstandard2.0/Microsoft.PowerShell.PSReadLine.Polyfiller.dll"
44-
}
45-
4645
$binaryModuleParams = @{
47-
Inputs = { Get-ChildItem PSReadLine/*.cs, PSReadLine/PSReadLine.csproj, PSReadLine/PSReadLineResources.resx, Polyfill/*.cs, Polyfill/Polyfill.csproj }
48-
Outputs = "PSReadLine/bin/$Configuration/netstandard2.0/Microsoft.PowerShell.PSReadLine.dll"
46+
Inputs = { Get-ChildItem PSReadLine/*.cs, PSReadLine/PSReadLine.csproj, PSReadLine/PSReadLineResources.resx }
47+
Outputs = "PSReadLine/bin/$Configuration/$targetFramework/Microsoft.PowerShell.PSReadLine.dll"
4948
}
5049

5150
$xUnitTestParams = @{
5251
Inputs = { Get-ChildItem test/*.cs, test/*.json, test/PSReadLine.Tests.csproj }
53-
Outputs = "test/bin/$Configuration/$TestFramework/PSReadLine.Tests.dll"
54-
}
55-
56-
<#
57-
Synopsis: Build the Polyfiller assembly
58-
#>
59-
task BuildPolyfiller @polyFillerParams {
60-
exec { dotnet publish -c $Configuration -f 'netstandard2.0' Polyfill }
61-
exec { dotnet publish -c $Configuration -f 'net6.0' Polyfill }
52+
Outputs = "test/bin/$Configuration/$targetFramework/PSReadLine.Tests.dll"
6253
}
6354

6455
<#
@@ -72,15 +63,15 @@ task BuildMainModule @binaryModuleParams {
7263
Synopsis: Build xUnit tests
7364
#>
7465
task BuildXUnitTests @xUnitTestParams {
75-
exec { dotnet publish -f $TestFramework -c $Configuration test }
66+
exec { dotnet publish -f $targetFramework -c $Configuration test }
7667
}
7768

7869
<#
7970
Synopsis: Run the unit tests
8071
#>
8172
task RunTests BuildMainModule, BuildXUnitTests, {
82-
Write-Verbose "Run tests targeting '$TestFramework' ..."
83-
Start-TestRun -Configuration $Configuration -Framework $TestFramework
73+
Write-Verbose "Run tests targeting $targetFramework ..."
74+
Start-TestRun -Configuration $Configuration -Framework $targetFramework
8475
}
8576

8677
<#
@@ -97,7 +88,7 @@ task CheckHelpContent -If $CheckHelpContent {
9788
<#
9889
Synopsis: Copy all of the files that belong in the module to one place in the layout for installation
9990
#>
100-
task LayoutModule BuildPolyfiller, BuildMainModule, {
91+
task LayoutModule BuildMainModule, {
10192
if (-not (Test-Path $targetDir -PathType Container)) {
10293
New-Item $targetDir -ItemType Directory -Force > $null
10394
}
@@ -115,17 +106,7 @@ task LayoutModule BuildPolyfiller, BuildMainModule, {
115106
Set-Content -Path (Join-Path $targetDir (Split-Path $file -Leaf)) -Value (ConvertTo-CRLF $content) -Force
116107
}
117108

118-
if (-not (Test-Path "$targetDir/netstd")) {
119-
New-Item "$targetDir/netstd" -ItemType Directory -Force > $null
120-
}
121-
if (-not (Test-Path "$targetDir/net6plus")) {
122-
New-Item "$targetDir/net6plus" -ItemType Directory -Force > $null
123-
}
124-
125-
Copy-Item "Polyfill/bin/$Configuration/netstandard2.0/Microsoft.PowerShell.PSReadLine.Polyfiller.dll" "$targetDir/netstd" -Force
126-
Copy-Item "Polyfill/bin/$Configuration/net6.0/Microsoft.PowerShell.PSReadLine.Polyfiller.dll" "$targetDir/net6plus" -Force
127-
128-
$binPath = "PSReadLine/bin/$Configuration/netstandard2.0/publish"
109+
$binPath = "PSReadLine/bin/$Configuration/$targetFramework/publish"
129110
Copy-Item $binPath/Microsoft.PowerShell.PSReadLine.dll $targetDir
130111
Copy-Item $binPath/Microsoft.PowerShell.Pager.dll $targetDir
131112

PSReadLine/Accessibility.cs

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Copyright (c) Microsoft Corporation. All rights reserved.
33
--********************************************************************/
44

5+
using System.Diagnostics;
56
using System.Runtime.InteropServices;
67

78
namespace Microsoft.PowerShell.Internal
@@ -10,14 +11,82 @@ internal class Accessibility
1011
{
1112
internal static bool IsScreenReaderActive()
1213
{
13-
bool returnValue = false;
14-
1514
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
1615
{
17-
PlatformWindows.SystemParametersInfo(PlatformWindows.SPI_GETSCREENREADER, 0, ref returnValue, 0);
16+
return IsAnyWindowsScreenReaderEnabled();
17+
}
18+
19+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
20+
{
21+
return IsVoiceOverEnabled();
22+
}
23+
24+
// TODO: Support Linux per https://code.visualstudio.com/docs/configure/accessibility/accessibility
25+
return false;
26+
}
27+
28+
private static bool IsAnyWindowsScreenReaderEnabled()
29+
{
30+
// The supposedly official way to check for a screen reader on
31+
// Windows is SystemParametersInfo(SPI_GETSCREENREADER, ...) but it
32+
// doesn't detect the in-box Windows Narrator and is otherwise known
33+
// to be problematic.
34+
//
35+
// Unfortunately, the alternative method used by Electron and
36+
// Chromium, where the relevant screen reader libraries (modules)
37+
// are checked for does not work in the context of PowerShell
38+
// because it relies on those applications injecting themselves into
39+
// the app. Which they do not because PowerShell is not a windowed
40+
// app, so we're stuck using the known-to-be-buggy way.
41+
bool spiScreenReader = false;
42+
PlatformWindows.SystemParametersInfo(PlatformWindows.SPI_GETSCREENREADER, 0, ref spiScreenReader, 0);
43+
if (spiScreenReader)
44+
{
45+
return true;
46+
}
47+
48+
// At least we can correctly check for Windows Narrator using the
49+
// NarratorRunning mutex. Windows Narrator is mostly not broken with
50+
// PSReadLine, not in the way that NVDA and VoiceOver are.
51+
if (PlatformWindows.IsMutexPresent("NarratorRunning"))
52+
{
53+
return true;
54+
}
55+
56+
return false;
57+
}
58+
59+
private static bool IsVoiceOverEnabled()
60+
{
61+
try
62+
{
63+
// Use the 'defaults' command to check if VoiceOver is enabled
64+
// This checks the com.apple.universalaccess preference for voiceOverOnOffKey
65+
ProcessStartInfo startInfo = new()
66+
{
67+
FileName = "defaults",
68+
Arguments = "read com.apple.universalaccess voiceOverOnOffKey",
69+
UseShellExecute = false,
70+
RedirectStandardOutput = true,
71+
RedirectStandardError = true,
72+
CreateNoWindow = true
73+
};
74+
75+
using Process process = Process.Start(startInfo);
76+
process.WaitForExit(250);
77+
if (process.HasExited && process.ExitCode == 0)
78+
{
79+
string output = process.StandardOutput.ReadToEnd().Trim();
80+
// VoiceOver is enabled if the value is 1
81+
return output == "1";
82+
}
83+
}
84+
catch
85+
{
86+
// If we can't determine the status, assume VoiceOver is not enabled
1887
}
1988

20-
return returnValue;
89+
return false;
2190
}
2291
}
2392
}

PSReadLine/BasicEditing.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public static void CancelLine(ConsoleKeyInfo? key = null, object arg = null)
8686
_singleton._current = _singleton._buffer.Length;
8787

8888
using var _ = _singleton._prediction.DisableScoped();
89-
_singleton.ForceRender();
89+
_singleton.Render(force: true);
9090

9191
_singleton._console.Write("\x1b[91m^C\x1b[0m");
9292

@@ -335,7 +335,7 @@ private bool AcceptLineImpl(bool validate)
335335

336336
if (renderNeeded)
337337
{
338-
ForceRender();
338+
Render(force: true);
339339
}
340340

341341
// Only run validation if we haven't before. If we have and status line shows an error,

PSReadLine/Changes.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
### [2.4.5] - 2025-10-22
2+
3+
- Replace `DOTNET_SKIP_FIRST_TIME_EXPERIENCE` with `DOTNET_NOLOGO` (#4916) (Thanks @xtqqczze!)
4+
- Add the `ScreenReaderModeEnabled` property to formatting (#4970)
5+
- Fix a null reference exception when showing parameter help (#4971)
6+
7+
[2.4.5]: https://github.com/PowerShell/PSReadLine/compare/v2.4.4-beta4...v2.4.5
8+
9+
### [2.4.4-beta4] - 2025-08-28
10+
11+
- Fix `IsMutexPresent()` to avoid incorrect use of `GetLastWin32Error()` (#4910)
12+
- Add screen reader support to PSReadLine (#4854)
13+
14+
[2.4.4-beta4]: https://github.com/PowerShell/PSReadLine/compare/v2.4.3-beta3...v2.4.4-beta4
15+
16+
### [2.4.3-beta3] - 2025-07-23
17+
18+
- Allow accepting the current input automatically from within an `OnIdle` event handler (#4830)
19+
- Add VS Code tasks and debug config (#4834, #4855)
20+
- Add bound check for the cursor top value to `InvokePrompt` (#4791) (Thanks @jftkcs!)
21+
- Fix typo in `SamplePSReadLineProfile.ps1` (#4725) (Thanks @mahir-cadirci!)
22+
- Fix line ending and cache some reflection operations (#4709)
23+
- Improve test reliability by making sure the PSReadLine one-time initialization is done (#4686) (Thanks @springcomp!)
24+
25+
[2.4.3-beta3]: https://github.com/PowerShell/PSReadLine/compare/v2.4.2-beta2...v2.4.3-beta3
26+
127
### [2.4.2-beta2] - 2025-04-16
228

329
- Add a private field to indicate if PSReadLine is initialized and ready (#4706)

PSReadLine/Cmdlets.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using System.Runtime.InteropServices;
1616
using System.Threading;
1717
using Microsoft.PowerShell.PSReadLine;
18+
using Microsoft.PowerShell.Internal;
1819
using AllowNull = System.Management.Automation.AllowNullAttribute;
1920

2021
namespace Microsoft.PowerShell
@@ -163,11 +164,6 @@ public class PSConsoleReadLineOptions
163164

164165
public const HistorySaveStyle DefaultHistorySaveStyle = HistorySaveStyle.SaveIncrementally;
165166

166-
/// <summary>
167-
/// The predictive suggestion feature is disabled by default.
168-
/// </summary>
169-
public const PredictionSource DefaultPredictionSource = PredictionSource.None;
170-
171167
public const PredictionViewStyle DefaultPredictionViewStyle = PredictionViewStyle.InlineView;
172168

173169
/// <summary>
@@ -195,7 +191,7 @@ static PSConsoleReadLineOptions()
195191

196192
// Our tests expect that the default inline-view color is set to the new color, so we configure
197193
// the color based on system environment only if we are not in test runs.
198-
if (AppDomain.CurrentDomain.FriendlyName is not "PSReadLine.Tests")
194+
if (AppDomain.CurrentDomain.FriendlyName is not "testhost")
199195
{
200196
DefaultInlinePredictionColor =
201197
Environment.OSVersion.Version.Build >= 22621 // on Windows 11 22H2 or newer versions
@@ -215,6 +211,7 @@ public PSConsoleReadLineOptions(string hostName, bool usingLegacyConsole)
215211
ResetColors();
216212
EditMode = DefaultEditMode;
217213
HistoryType = DefaultHistoryType;
214+
ScreenReaderModeEnabled = Accessibility.IsScreenReaderActive();
218215
ContinuationPrompt = DefaultContinuationPrompt;
219216
ContinuationPromptColor = Console.ForegroundColor;
220217
ExtraPromptLineCount = DefaultExtraPromptLineCount;
@@ -560,6 +557,8 @@ public object ListPredictionTooltipColor
560557

561558
public bool TerminateOrphanedConsoleApps { get; set; }
562559

560+
public bool ScreenReaderModeEnabled { get; set; }
561+
563562
internal string _defaultTokenColor;
564563
internal string _commentColor;
565564
internal string _keywordColor;
@@ -888,6 +887,14 @@ public SwitchParameter TerminateOrphanedConsoleApps
888887
}
889888
internal SwitchParameter? _terminateOrphanedConsoleApps;
890889

890+
[Parameter]
891+
public SwitchParameter EnableScreenReaderMode
892+
{
893+
get => _enableScreenReaderMode.GetValueOrDefault();
894+
set => _enableScreenReaderMode = value;
895+
}
896+
internal SwitchParameter? _enableScreenReaderMode;
897+
891898
[ExcludeFromCodeCoverage]
892899
protected override void EndProcessing()
893900
{

0 commit comments

Comments
 (0)