diff --git a/QuickShell.Core.Tests/RunGlobalQueryTests.cs b/QuickShell.Core.Tests/RunGlobalQueryTests.cs
index 7ae7e340..a282d9c2 100644
--- a/QuickShell.Core.Tests/RunGlobalQueryTests.cs
+++ b/QuickShell.Core.Tests/RunGlobalQueryTests.cs
@@ -1,15 +1,9 @@
using QuickShell.Services;
-
-
-
+
namespace QuickShell.Core.Tests;
-
-
-
+
public sealed class RunGlobalQueryTests
-
{
-
[Theory]
[InlineData("quickshell")]
@@ -21,85 +15,56 @@ public sealed class RunGlobalQueryTests
[InlineData("qs")]
public void TryActivate_PluginName_EntersBrowseMode(string query)
-
{
-
Assert.True(RunGlobalQuery.TryActivate(query, rawQuery: null, out var remaining));
Assert.Equal(string.Empty, remaining);
-
}
-
-
-
+
[Fact]
public void TryActivate_PluginNameWithFilter_StripsPrefix()
-
{
-
Assert.True(RunGlobalQuery.TryActivate("quick shell api", rawQuery: null, out var remaining));
Assert.Equal("api", remaining);
-
}
-
-
-
+
[Fact]
public void TryActivate_RawQueryFallback_ActivatesWhenSearchEmpty()
-
{
-
Assert.True(RunGlobalQuery.TryActivate(string.Empty, "Quick Shell", out var remaining));
Assert.Equal(string.Empty, remaining);
-
}
-
-
-
+
[Fact]
public void TryActivate_UnrelatedQuery_DoesNotActivate()
-
{
-
Assert.False(RunGlobalQuery.TryActivate("my api project", rawQuery: null, out var remaining));
Assert.Equal("my api project", remaining);
-
}
-
-
-
+
[Fact]
public void ShouldSuppressEmptyGlobalQuery_BlocksBareGlobalSearch()
-
{
-
var context = new QueryActivationContext(HasActionKeyword: false, Search: string.Empty);
Assert.True(RunGlobalQuery.ShouldSuppressEmptyGlobalQuery(context));
-
}
-
-
-
+
[Fact]
public void ShouldSuppressEmptyGlobalQuery_AllowsActionKeywordBrowse()
-
{
-
var context = new QueryActivationContext(HasActionKeyword: true, Search: string.Empty);
Assert.False(RunGlobalQuery.ShouldSuppressEmptyGlobalQuery(context));
-
}
-
}
diff --git a/QuickShell.Core.Tests/TestQuickShellServicesFactory.cs b/QuickShell.Core.Tests/TestQuickShellServicesFactory.cs
index d9dcf9e0..63fe4299 100644
--- a/QuickShell.Core.Tests/TestQuickShellServicesFactory.cs
+++ b/QuickShell.Core.Tests/TestQuickShellServicesFactory.cs
@@ -187,5 +187,4 @@ private static (AppDataPaths appDataPaths, TerminalLaunchGlyphs glyphs, Terminal
var prewarm = new TerminalCatalogPrewarm(bundle.Catalog);
return (appDataPaths, glyphs, listIcons, prewarm);
}
-
}
diff --git a/QuickShell.Core.Tests/WorkspaceTrustCommandTests.cs b/QuickShell.Core.Tests/WorkspaceTrustCommandTests.cs
index 9d388ab3..d79442ce 100644
--- a/QuickShell.Core.Tests/WorkspaceTrustCommandTests.cs
+++ b/QuickShell.Core.Tests/WorkspaceTrustCommandTests.cs
@@ -105,8 +105,7 @@ private static (QuickShellServices Services, QuickShellLifetime Lifetime, Shortc
lifetime);
return (services, lifetime, drafts);
}
-
-
+
private static TerminalShortcut CreateWorkspace() =>
new()
{
diff --git a/QuickShell.Core/Models/TerminalShortcut.cs b/QuickShell.Core/Models/TerminalShortcut.cs
index 3539314e..2573a99d 100644
--- a/QuickShell.Core/Models/TerminalShortcut.cs
+++ b/QuickShell.Core/Models/TerminalShortcut.cs
@@ -1,84 +1,47 @@
namespace QuickShell.Models;
-
-
-
+
internal sealed class TerminalShortcut
-
{
-
public string Id { get; set; } = string.Empty;
-
-
-
+
public string Name { get; set; } = string.Empty;
-
-
-
+
public string? Abbreviation { get; set; }
-
-
-
+
public string Directory { get; set; } = string.Empty;
-
-
-
+
public string? Command { get; set; }
-
-
-
+
// "default" means use extension-level default terminal setting.
public string Terminal { get; set; } = "default";
-
-
-
+
// Optional Windows Terminal profile name for terminal=wt/default->wt.
public string? WtProfile { get; set; }
-
-
-
+
public bool RunAsAdmin { get; set; }
-
-
-
+
public bool IsPinned { get; set; }
-
-
-
+
// Lower number means higher in the favorites section.
public int? PinOrder { get; set; }
-
-
-
+
public DateTime? LastUsedUtc { get; set; }
-
-
-
+
/// One or more terminal launches for this workspace. When empty on disk, synthesized from legacy fields on load.
-
public List Launches { get; set; } = [];
-
-
-
+
/// Optional dev server URL opened in the browser when the workspace runs.
public string? DevServerUrl { get; set; }
-
-
-
+
/// When true, opens whenever the full workspace runs.
-
public bool OpenDevServerOnLaunch { get; set; }
-
-
-
+
/// Optional repository URL opened from the workspace action menu.
-
public string? RepoUrl { get; set; }
-
-
-
+
///
/// One or more GUI companion apps. When empty on disk, synthesized from the legacy
/// scalar companion fields on load (see CompanionAppNormalization).
@@ -103,7 +66,6 @@ internal sealed class TerminalShortcut
/// for the workspace directory. Mirrored from the first entry.
///
public string? CompanionAppArguments { get; set; }
-
}
diff --git a/QuickShell.Core/Models/WorkspaceSecurityMetadata.cs b/QuickShell.Core/Models/WorkspaceSecurityMetadata.cs
index 4aa06635..7f6dc3de 100644
--- a/QuickShell.Core/Models/WorkspaceSecurityMetadata.cs
+++ b/QuickShell.Core/Models/WorkspaceSecurityMetadata.cs
@@ -10,7 +10,6 @@ internal sealed record WorkspaceSecurityMetadata
public bool IsTrusted { get; init; } = true;
public long Revision { get; init; } = 1;
-
}
internal sealed record StoredWorkspace(
diff --git a/QuickShell.Core/Services/ShortcutLaunchFormJson.cs b/QuickShell.Core/Services/ShortcutLaunchFormJson.cs
index e1596f14..f2077425 100644
--- a/QuickShell.Core/Services/ShortcutLaunchFormJson.cs
+++ b/QuickShell.Core/Services/ShortcutLaunchFormJson.cs
@@ -1,54 +1,33 @@
using QuickShell.Core.Services;
namespace QuickShell.Services;
-
-
-
+
internal static partial class ShortcutLaunchFormJson
-
{
-
private const string CommandColumnWidth = "2";
private const string ProfileColumnWidth = "2";
private const string AdminColumnWidth = "auto";
-
-
-
+
public sealed class LaunchRowDraft
-
{
-
public string Label { get; set; } = string.Empty;
-
-
-
+
public string Command { get; set; } = string.Empty;
-
-
-
+
public string LaunchTarget { get; set; } = "default";
-
-
-
+
public bool RunAsAdmin { get; set; }
-
-
-
+
public bool IsEnabled { get; set; } = true;
-
}
-
-
-
+
public static string BuildCommandRowsJson(
IReadOnlyList rows,
string terminalChoices,
LaunchEditorText text)
-
{
-
var blocks = new List();
var tipAdmin = Escape(WorkspaceFormTooltips.RunAsAdmin);
@@ -122,11 +101,8 @@ public static string BuildCommandRowsJson(
blocks.Add("""{ "type": "Container", "spacing": "Medium", "items": [] }""");
return string.Join(',', blocks);
-
}
-
-
-
+
public static string BuildCommandsSectionHeaderJson(LaunchEditorText text) =>
$$"""
{
@@ -158,25 +134,16 @@ public static string BuildCommandsSectionJson(string commandRows, string suggest
""";
public static string BuildLaunchRowsJson(IReadOnlyList launches, string terminalChoices)
-
{
-
if (launches.Count == 0)
-
{
-
return string.Empty;
-
}
-
-
-
+
var blocks = new List();
for (var i = 0; i < launches.Count; i++)
-
{
-
var launch = launches[i];
var escapedLabel = Escape(launch.Label);
@@ -188,9 +155,7 @@ public static string BuildLaunchRowsJson(IReadOnlyList launches,
var adminValue = launch.RunAsAdmin ? "true" : "false";
var enabledValue = launch.IsEnabled ? "true" : "false";
-
-
-
+
var labelInput = $$"""
{
@@ -206,13 +171,9 @@ public static string BuildLaunchRowsJson(IReadOnlyList launches,
}
""";
-
-
-
+
var commandInput = BuildCommandInputWithClear(i, literalValue: escapedCommand, removeTooltip: FormActionGlyphs.ClearCommandTooltip);
-
-
-
+
var adminInput = $$"""
{
@@ -232,9 +193,7 @@ public static string BuildLaunchRowsJson(IReadOnlyList launches,
}
""";
-
-
-
+
var enabledInput = $$"""
{
@@ -254,9 +213,7 @@ public static string BuildLaunchRowsJson(IReadOnlyList launches,
}
""";
-
-
-
+
blocks.Add($$"""
{
@@ -518,25 +475,16 @@ public static string BuildLaunchRowsJson(IReadOnlyList launches,
}
""");
-
}
-
-
-
+
return string.Join(',', blocks);
-
}
-
-
-
+
public static string WrapLaunchRowsForTest(string launchRows) =>
$$"""{ "type": "AdaptiveCard", "version": "1.6", "body": [{{launchRows}}] }""";
-
-
-
+
private static string Escape(string? value) =>
(value ?? string.Empty).Replace("\\", "\\\\").Replace("\"", "\\\"");
-
}
diff --git a/QuickShell.Core/Services/TerminalCatalog.cs b/QuickShell.Core/Services/TerminalCatalog.cs
index a68aaabb..c460e7a1 100644
--- a/QuickShell.Core/Services/TerminalCatalog.cs
+++ b/QuickShell.Core/Services/TerminalCatalog.cs
@@ -63,8 +63,7 @@ public TerminalCatalog(IWtProfilesService profiles)
{
_profiles = profiles ?? throw new ArgumentNullException(nameof(profiles));
}
-
-
+
string ITerminalCatalog.EncodeLaunchTargetId(TerminalShortcut shortcut) =>
EncodeLaunchTargetId(shortcut);
@@ -87,8 +86,7 @@ WorkspaceEntry ITerminalCatalog.ResolveLaunchEntry(
IReadOnlyList orderedLaunches,
int index) =>
ResolveLaunchEntry(entry, orderedLaunches, index);
-
-
+
public IReadOnlyList GetLaunchTargets(bool includeDefaultChoice = false)
{
var snapshot = EnsureCached();
diff --git a/QuickShell.Core/Services/TerminalHostIds.cs b/QuickShell.Core/Services/TerminalHostIds.cs
index 1859a3d2..31e3f391 100644
--- a/QuickShell.Core/Services/TerminalHostIds.cs
+++ b/QuickShell.Core/Services/TerminalHostIds.cs
@@ -1,70 +1,72 @@
-namespace QuickShell.Services;
-
-internal static class TerminalHostIds
-{
- public const string LetWindowsChoose = "system";
-
- public const string WindowsTerminal = "wt";
-
- public const string WindowsConsoleHost = "conhost";
-
- public const string IntelligentTerminal = "it";
-
- public const string DefaultProfile = "__default__";
-
- public static string ResolveEffectiveApplication(string terminalApplicationId)
- {
- if (terminalApplicationId.Equals(LetWindowsChoose, StringComparison.OrdinalIgnoreCase))
- {
- return WindowsDefaultTerminalReader.ReadApplicationId();
- }
-
- return terminalApplicationId;
- }
-
- public static bool UsesWindowsTerminalProfiles(string terminalApplicationId) =>
- !ResolveEffectiveApplication(terminalApplicationId)
- .Equals(WindowsConsoleHost, StringComparison.OrdinalIgnoreCase);
-
- public static bool IsWindowsTerminalProfilePrefix(string idPrefix) =>
- idPrefix.Equals("wt", StringComparison.OrdinalIgnoreCase)
- || idPrefix.Equals("wtp", StringComparison.OrdinalIgnoreCase)
- || idPrefix.Equals("wtu", StringComparison.OrdinalIgnoreCase);
-
- public static bool IsSupportedProfilePrefix(string idPrefix) =>
- IsWindowsTerminalProfilePrefix(idPrefix)
- || idPrefix.Equals(IntelligentTerminal, StringComparison.OrdinalIgnoreCase);
-
- public static string HostExecutable(string terminalApplicationId)
- {
- var effective = ResolveEffectiveApplication(terminalApplicationId);
- return effective.Equals(IntelligentTerminal, StringComparison.OrdinalIgnoreCase)
- ? "wtai.exe"
- : "wt.exe";
- }
-
- public static string ProfileIdPrefix(string terminalApplicationId)
- {
- var effective = ResolveEffectiveApplication(terminalApplicationId);
- return effective.Equals(IntelligentTerminal, StringComparison.OrdinalIgnoreCase)
- ? IntelligentTerminal
- : WindowsTerminal;
- }
-
- public static string SourceLabel(string terminalApplicationId)
- {
- if (terminalApplicationId.Equals(LetWindowsChoose, StringComparison.OrdinalIgnoreCase))
- {
- return "Let Windows choose";
- }
-
- if (terminalApplicationId.Equals(WindowsConsoleHost, StringComparison.OrdinalIgnoreCase))
- {
- return "Windows Console Host";
- }
-
- return ResolveEffectiveApplication(terminalApplicationId).Equals(IntelligentTerminal, StringComparison.OrdinalIgnoreCase)
- ? "Intelligent Terminal"
- : "Windows Terminal";
- }
-}
+namespace QuickShell.Services;
+
+internal static class TerminalHostIds
+{
+ public const string LetWindowsChoose = "system";
+
+ public const string WindowsTerminal = "wt";
+
+ public const string WindowsConsoleHost = "conhost";
+
+ public const string IntelligentTerminal = "it";
+
+ public const string DefaultProfile = "__default__";
+
+ public static string ResolveEffectiveApplication(string terminalApplicationId)
+ {
+ if (terminalApplicationId.Equals(LetWindowsChoose, StringComparison.OrdinalIgnoreCase))
+ {
+ return WindowsDefaultTerminalReader.ReadApplicationId();
+ }
+
+ return terminalApplicationId;
+ }
+
+ public static bool UsesWindowsTerminalProfiles(string terminalApplicationId) =>
+ !ResolveEffectiveApplication(terminalApplicationId)
+ .Equals(WindowsConsoleHost, StringComparison.OrdinalIgnoreCase);
+
+ public static bool IsWindowsTerminalProfilePrefix(string idPrefix) =>
+ idPrefix.Equals("wt", StringComparison.OrdinalIgnoreCase)
+ || idPrefix.Equals("wtp", StringComparison.OrdinalIgnoreCase)
+ || idPrefix.Equals("wtu", StringComparison.OrdinalIgnoreCase);
+
+ public static bool IsSupportedProfilePrefix(string idPrefix) =>
+ IsWindowsTerminalProfilePrefix(idPrefix)
+ || idPrefix.Equals(IntelligentTerminal, StringComparison.OrdinalIgnoreCase);
+
+ public static string HostExecutable(string terminalApplicationId)
+ {
+ var effective = ResolveEffectiveApplication(terminalApplicationId);
+
+ return effective.Equals(IntelligentTerminal, StringComparison.OrdinalIgnoreCase)
+ ? "wtai.exe"
+ : "wt.exe";
+ }
+
+ public static string ProfileIdPrefix(string terminalApplicationId)
+ {
+ var effective = ResolveEffectiveApplication(terminalApplicationId);
+
+ return effective.Equals(IntelligentTerminal, StringComparison.OrdinalIgnoreCase)
+ ? IntelligentTerminal
+ : WindowsTerminal;
+ }
+
+ public static string SourceLabel(string terminalApplicationId)
+ {
+ if (terminalApplicationId.Equals(LetWindowsChoose, StringComparison.OrdinalIgnoreCase))
+ {
+ return "Let Windows choose";
+ }
+
+ if (terminalApplicationId.Equals(WindowsConsoleHost, StringComparison.OrdinalIgnoreCase))
+ {
+ return "Windows Console Host";
+ }
+
+ return ResolveEffectiveApplication(terminalApplicationId).Equals(IntelligentTerminal, StringComparison.OrdinalIgnoreCase)
+ ? "Intelligent Terminal"
+ : "Windows Terminal";
+ }
+}
diff --git a/QuickShell.Core/Services/WorkspaceRepositorySnapshot.cs b/QuickShell.Core/Services/WorkspaceRepositorySnapshot.cs
index 40517cd6..4aa13ebc 100644
--- a/QuickShell.Core/Services/WorkspaceRepositorySnapshot.cs
+++ b/QuickShell.Core/Services/WorkspaceRepositorySnapshot.cs
@@ -99,6 +99,20 @@ public IEnumerable SearchTaskActions(string query, ITermina
return [];
}
+ var matches = CollectMatchingTaskActions(tokens, catalog);
+ if (matches.Count == 0)
+ {
+ return [];
+ }
+
+ matches.Sort(CompareTaskActions);
+ return matches.ToArray();
+ }
+
+ private List CollectMatchingTaskActions(
+ IReadOnlyList tokens,
+ ITerminalCatalog catalog)
+ {
List? matches = null;
foreach (var shortcut in Shortcuts)
{
@@ -107,53 +121,58 @@ public IEnumerable SearchTaskActions(string query, ITermina
continue;
}
- bool? requiresRepair = null;
- foreach (var launch in shortcut.Launches)
+ AppendMatchingTaskActions(shortcut, tokens, catalog, ref matches);
+ }
+
+ return matches ?? [];
+ }
+
+ private static void AppendMatchingTaskActions(
+ TerminalShortcut shortcut,
+ IReadOnlyList tokens,
+ ITerminalCatalog catalog,
+ ref List? matches)
+ {
+ bool? requiresRepair = null;
+ foreach (var launch in shortcut.Launches)
+ {
+ if (!launch.IsEnabled)
+ {
+ continue;
+ }
+
+ var score = ComputeTaskActionScore(shortcut, launch, tokens, catalog);
+ if (score <= 0)
{
- if (!launch.IsEnabled)
- {
- continue;
- }
-
- var score = ComputeTaskActionScore(shortcut, launch, tokens, catalog);
- if (score <= 0)
- {
- continue;
- }
-
- requiresRepair ??= ShortcutHealth.WouldNeedRepair(
- shortcut,
- requireDirectoryExists: false);
- if (requiresRepair.Value)
- {
- break;
- }
+ continue;
+ }
- matches ??= [];
- matches.Add(CreateTaskAction(shortcut, launch, score));
+ requiresRepair ??= ShortcutHealth.WouldNeedRepair(
+ shortcut,
+ requireDirectoryExists: false);
+ if (requiresRepair.Value)
+ {
+ break;
}
- }
- if (matches is null)
- {
- return [];
+ matches ??= [];
+ matches.Add(CreateTaskAction(shortcut, launch, score));
}
+ }
- matches.Sort(static (left, right) =>
+ private static int CompareTaskActions(WorkspaceTaskAction left, WorkspaceTaskAction right)
+ {
+ var byScore = right.Score.CompareTo(left.Score);
+ if (byScore != 0)
{
- var byScore = right.Score.CompareTo(left.Score);
- if (byScore != 0)
- {
- return byScore;
- }
+ return byScore;
+ }
- var byName = string.Compare(
- left.Workspace.Name,
- right.Workspace.Name,
- StringComparison.OrdinalIgnoreCase);
- return byName != 0 ? byName : left.Launch.Order.CompareTo(right.Launch.Order);
- });
- return matches.ToArray();
+ var byName = string.Compare(
+ left.Workspace.Name,
+ right.Workspace.Name,
+ StringComparison.OrdinalIgnoreCase);
+ return byName != 0 ? byName : left.Launch.Order.CompareTo(right.Launch.Order);
}
private static bool Matches(TerminalShortcut shortcut, string query, int queryStart, int queryLength)
@@ -245,7 +264,6 @@ private static int ComputeTaskActionScore(
ScoreToken(profileLabel, token, exact: 250, prefix: 175, contains: 90) +
ScoreToken(launch.WtProfile, token, exact: 220, prefix: 160, contains: 80);
-
if (workspaceScore + launchScore == 0)
{
return 0;
diff --git a/QuickShell.Run/QuickShellRunSettingsWindow.cs b/QuickShell.Run/QuickShellRunSettingsWindow.cs
index 4455a447..1a2285e2 100644
--- a/QuickShell.Run/QuickShellRunSettingsWindow.cs
+++ b/QuickShell.Run/QuickShellRunSettingsWindow.cs
@@ -5,17 +5,11 @@
using System.Windows;
using System.Windows.Controls;
-
-
-
+
namespace QuickShell.Run;
-
-
-
+
internal sealed class QuickShellRunSettingsWindow : Window
-
{
-
private readonly QuickShellSettingsReader _settings;
private readonly IShortcutRepository _shortcuts;
@@ -37,9 +31,7 @@ internal sealed class QuickShellRunSettingsWindow : Window
private readonly TextBlock _statusText;
private SettingsSnapshot _baseline;
-
-
-
+
public QuickShellRunSettingsWindow(
QuickShellSettingsReader settings,
@@ -49,9 +41,7 @@ public QuickShellRunSettingsWindow(
IProjectAnalysisService projectAnalysis,
ITerminalCatalog catalog)
-
{
-
_settings = settings;
_shortcuts = shortcuts;
@@ -71,15 +61,11 @@ public QuickShellRunSettingsWindow(
WindowStartupLocation = WindowStartupLocation.CenterScreen;
ResizeMode = ResizeMode.NoResize;
-
-
-
+
var root = new StackPanel { Margin = new Thickness(16) };
root.Children.Add(Heading("Terminal defaults"));
-
-
-
+
root.Children.Add(Label("Terminal application"));
_terminalAppBox = Combo(RunTerminalChoices.GetTerminalApplicationChoices(_catalog));
@@ -87,37 +73,27 @@ public QuickShellRunSettingsWindow(
_terminalAppBox.SelectionChanged += (_, _) => ReloadProfileChoices();
root.Children.Add(_terminalAppBox);
-
-
-
+
root.Children.Add(Label("Default profile"));
_defaultProfileBox = new ComboBox
-
{
-
DisplayMemberPath = "Label",
SelectedValuePath = "Id",
Margin = new Thickness(0, 0, 0, 8),
-
};
root.Children.Add(_defaultProfileBox);
-
-
-
+
root.Children.Add(Heading("Git launch"));
_blockDirtyBranchBox = new CheckBox
-
{
-
Content = "Block launch when dirty and branch would change",
Margin = new Thickness(0, 0, 0, 8),
-
};
root.Children.Add(_blockDirtyBranchBox);
@@ -125,35 +101,25 @@ public QuickShellRunSettingsWindow(
root.Children.Add(Help(
"When a worktree target branch differs from HEAD, block launch if the working tree has uncommitted changes."));
-
-
-
+
root.Children.Add(Heading("Home list"));
_showRecentsBox = new CheckBox
-
{
-
Content = "Show recent workspaces",
Margin = new Thickness(0, 0, 0, 8),
-
};
root.Children.Add(_showRecentsBox);
-
-
-
+
root.Children.Add(Heading("Multiple commands"));
_singleWindowTabsBox = new CheckBox
-
{
-
Content = "Open multiple commands in one Windows Terminal window",
Margin = new Thickness(0, 0, 0, 8),
-
};
root.Children.Add(_singleWindowTabsBox);
@@ -161,9 +127,7 @@ public QuickShellRunSettingsWindow(
root.Children.Add(Help(
"When supported, extra commands open as tabs in the same window. Mixed elevation or Console Host still opens separate windows."));
-
-
-
+
root.Children.Add(Heading("Shortcuts"));
root.Children.Add(TooltipButton(
@@ -189,13 +153,9 @@ public QuickShellRunSettingsWindow(
"Replace every shortcut with the contents of a JSON file.",
() => ImportShortcuts(replace: true)));
-
-
-
+
root.Children.Add(new Separator { Margin = new Thickness(0, 8, 0, 8) });
-
-
-
+
root.Children.Add(TooltipButton(
"Open shortcuts.json",
@@ -211,25 +171,18 @@ public QuickShellRunSettingsWindow(
"Open the folder that stores shortcuts and settings.",
() => RunFileDialogs.OpenFolder(_shortcuts.ConfigDirectory)));
-
-
-
+
_statusText = new TextBlock
-
{
-
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 12, 0, 12),
Foreground = System.Windows.Media.Brushes.Gray,
-
};
root.Children.Add(_statusText);
-
-
-
+
var buttons = new StackPanel
{
Orientation = Orientation.Horizontal,
@@ -261,23 +214,16 @@ public QuickShellRunSettingsWindow(
buttons.Children.Add(save);
buttons.Children.Add(done);
root.Children.Add(buttons);
-
-
-
+
Content = root;
LoadCurrentValues();
_baseline = CaptureSnapshot();
-
}
-
-
-
+
private void LoadCurrentValues()
-
{
-
_terminalAppBox.SelectedValue = _settings.TerminalApplicationId;
ReloadProfileChoices();
@@ -289,15 +235,10 @@ private void LoadCurrentValues()
_showRecentsBox.IsChecked = QuickShellRecentSettings.IsEnabled(_settings.ReadRecentWorkspaceCount());
_singleWindowTabsBox.IsChecked = !_settings.ReadSeparateWindowsForMultiLaunch();
-
}
-
-
-
+
private void RestoreBaseline()
-
{
-
_settings.SaveTerminalDefaults(_baseline.TerminalApp, _baseline.DefaultProfile);
_settings.SaveBlockDirtyBranchSwitch(_baseline.BlockDirtyBranch);
@@ -305,11 +246,8 @@ private void RestoreBaseline()
_settings.SaveRecentWorkspaceCount(_baseline.RecentCount);
_settings.SaveMultiLaunchPresentation(_baseline.SingleWindowTabs);
-
}
-
-
-
+
private SettingsSnapshot CaptureSnapshot() =>
new(
@@ -323,13 +261,9 @@ private SettingsSnapshot CaptureSnapshot() =>
QuickShellRecentSettings.FromEnabled(_showRecentsBox.IsChecked == true),
_singleWindowTabsBox.IsChecked == true);
-
-
-
+
private void ReloadProfileChoices()
-
{
-
var app = _terminalAppBox.SelectedValue as string ?? _settings.TerminalApplicationId;
var selected = _defaultProfileBox.SelectedValue as string ?? _settings.DefaultProfileId;
@@ -337,15 +271,10 @@ private void ReloadProfileChoices()
_defaultProfileBox.Items.Clear();
foreach (var choice in RunTerminalChoices.GetDefaultProfileChoices(_catalog, app))
-
{
-
_defaultProfileBox.Items.Add(new { choice.Id, choice.Label });
-
}
-
-
-
+
_defaultProfileBox.SelectedValue = RunTerminalChoices.GetDefaultProfileChoices(_catalog, app)
.Any(choice => choice.Id.Equals(selected, StringComparison.OrdinalIgnoreCase))
@@ -353,11 +282,8 @@ private void ReloadProfileChoices()
? selected
: TerminalHostIds.DefaultProfile;
-
}
-
-
-
+
private bool HasUnsavedChanges()
{
var current = CaptureSnapshot();
@@ -369,9 +295,7 @@ private bool HasUnsavedChanges()
}
private bool Save()
-
{
-
var app = _terminalAppBox.SelectedValue as string ?? TerminalHostIds.LetWindowsChoose;
var profile = _defaultProfileBox.SelectedValue as string ?? TerminalHostIds.DefaultProfile;
@@ -389,79 +313,46 @@ private bool Save()
_baseline = CaptureSnapshot();
return true;
-
}
-
-
-
+
private void ExportShortcuts()
-
{
-
if (RunFileDialogs.TryExportShortcuts(_shortcuts, this, out var message))
-
{
-
SetStatus(message);
-
}
-
}
-
-
-
+
private void ImportShortcuts(bool replace)
-
{
-
if (RunFileDialogs.TryImportShortcuts(_shortcuts, this, replace, out var message)
&& !string.IsNullOrWhiteSpace(message))
-
{
-
SetStatus(message);
-
}
-
}
-
-
-
+
private void SetStatus(string message) => _statusText.Text = message;
-
-
-
+
private static TextBlock Heading(string text) => new()
-
{
-
Text = text,
FontWeight = FontWeights.SemiBold,
Margin = new Thickness(0, 12, 0, 8),
-
};
-
-
-
+
private static TextBlock Label(string text) => new()
-
{
-
Text = text,
Margin = new Thickness(0, 0, 0, 4),
-
};
-
-
-
+
private static TextBlock Help(string text) => new()
-
{
-
Text = text,
TextWrapping = TextWrapping.Wrap,
@@ -471,51 +362,31 @@ private void ImportShortcuts(bool replace)
Foreground = System.Windows.Media.Brushes.Gray,
FontSize = 12,
-
};
-
-
-
+
private static ComboBox Combo(IReadOnlyList<(string Id, string Label)> choices)
-
{
-
var box = new ComboBox
-
{
-
DisplayMemberPath = "Label",
SelectedValuePath = "Id",
Margin = new Thickness(0, 0, 0, 8),
-
};
foreach (var choice in choices)
-
{
-
box.Items.Add(new { choice.Id, choice.Label });
-
}
-
-
-
+
return box;
-
}
-
-
-
+
private static Button TooltipButton(string text, string tooltip, Action action)
-
{
-
var button = new Button
-
{
-
Content = text,
HorizontalAlignment = HorizontalAlignment.Stretch,
@@ -525,17 +396,13 @@ private static Button TooltipButton(string text, string tooltip, Action action)
MinWidth = 220,
ToolTip = tooltip,
-
};
button.Click += (_, _) => action();
return button;
-
}
-
-
-
+
private readonly record struct SettingsSnapshot(
string TerminalApp,
@@ -547,55 +414,34 @@ private readonly record struct SettingsSnapshot(
int RecentCount,
bool SingleWindowTabs);
-
}
-
-
-
+
internal static class QuickShellRunSettingsDialog
-
{
-
public static void Show(
QuickShellSettingsReader settings,
IShortcutRepository shortcuts,
IProjectAnalysisService projectAnalysis,
ITerminalCatalog catalog)
-
{
-
void ShowWindow()
-
{
-
var window = new QuickShellRunSettingsWindow(settings, shortcuts, projectAnalysis, catalog);
window.ShowDialog();
-
}
-
-
-
+
var app = Application.Current;
if (app?.Dispatcher.CheckAccess() == true)
-
{
-
ShowWindow();
-
}
-
else
-
{
-
app?.Dispatcher.Invoke(ShowWindow);
-
}
-
}
-
}
diff --git a/QuickShell/Services/SectionListItems.cs b/QuickShell/Services/SectionListItems.cs
index 2ba19ce2..de367875 100644
--- a/QuickShell/Services/SectionListItems.cs
+++ b/QuickShell/Services/SectionListItems.cs
@@ -1,40 +1,39 @@
-using Microsoft.CommandPalette.Extensions;
-using Microsoft.CommandPalette.Extensions.Toolkit;
-
-namespace QuickShell.Services;
-
-///
-/// Emits CmdPal section headers per PowerToys PR #43952: a row
-/// (no command, non-empty section/title) renders the visible header; stamping
-/// on normal items does not.
-///
-internal static class SectionListItems
-{
- public static IEnumerable InSection(string sectionTitle, IEnumerable items)
- {
- var materialized = items.ToList();
- if (materialized.Count == 0)
- {
- return materialized;
- }
-
- if (string.IsNullOrWhiteSpace(sectionTitle))
- {
- return materialized;
- }
-
- return PrependHeader(sectionTitle, materialized);
- }
-
- public static IEnumerable PrependHeader(string sectionTitle, IReadOnlyList items)
- {
- yield return CreateHeader(sectionTitle);
- foreach (var item in items)
- {
- yield return item;
- }
- }
-
- public static Separator CreateHeader(string sectionTitle) => new(sectionTitle);
-}
-
\ No newline at end of file
+using Microsoft.CommandPalette.Extensions;
+using Microsoft.CommandPalette.Extensions.Toolkit;
+
+namespace QuickShell.Services;
+
+///
+/// Emits CmdPal section headers per PowerToys PR #43952: a row
+/// (no command, non-empty section/title) renders the visible header; stamping
+/// on normal items does not.
+///
+internal static class SectionListItems
+{
+ public static IEnumerable InSection(string sectionTitle, IEnumerable items)
+ {
+ var materialized = items.ToList();
+ if (materialized.Count == 0)
+ {
+ return materialized;
+ }
+
+ if (string.IsNullOrWhiteSpace(sectionTitle))
+ {
+ return materialized;
+ }
+
+ return PrependHeader(sectionTitle, materialized);
+ }
+
+ public static IEnumerable PrependHeader(string sectionTitle, IReadOnlyList items)
+ {
+ yield return CreateHeader(sectionTitle);
+ foreach (var item in items)
+ {
+ yield return item;
+ }
+ }
+
+ public static Separator CreateHeader(string sectionTitle) => new(sectionTitle);
+}
diff --git a/scripts/LogoAssetGenerator/Program.cs b/scripts/LogoAssetGenerator/Program.cs
index 77f24938..7da8e4df 100644
--- a/scripts/LogoAssetGenerator/Program.cs
+++ b/scripts/LogoAssetGenerator/Program.cs
@@ -239,8 +239,8 @@ static void RenderPosterLogoFromBitmap(string outDir, string fileName, SKBitmap
DrawPosterKicker(canvas, renderWidth, kickerY, kickerSize);
DrawPosterBranding(canvas, renderWidth, titleY, taglineY, titleSize, taglineSize);
- var iconBandTop = textBlockBottom + height * 0.02f * ss;
- var iconBandBottom = contentBottom - height * 0.11f * ss;
+ var iconBandTop = textBlockBottom + (height * 0.02f * ss);
+ var iconBandBottom = contentBottom - (height * 0.11f * ss);
var iconBandHeight = iconBandBottom - iconBandTop;
var iconWidthTarget = width * 0.68f * ss;
var scaleByWidth = iconWidthTarget / bounds.Width;
@@ -260,7 +260,7 @@ static void RenderPosterLogoFromBitmap(string outDir, string fileName, SKBitmap
var badgeSize = width * 0.021f * ss;
var badgeBlockHeight = height * 0.088f * ss;
- var badgeRowY = iconTop + scaledHeight + height * 0.02f * ss + (badgeBlockHeight / 2f);
+ var badgeRowY = iconTop + scaledHeight + (height * 0.02f * ss) + (badgeBlockHeight / 2f);
DrawPosterFeatureBadges(canvas, renderWidth, badgeRowY, badgeSize);
DrawPosterPaletteMockup(canvas, renderWidth, renderHeight, contentBottom);
@@ -297,8 +297,8 @@ static void RenderPosterLogoFromPicture(string outDir, string fileName, SKPictur
DrawPosterBranding(canvas, renderWidth, titleY, taglineY, titleSize, taglineSize);
// Size icon to fill the band between headline and badge row.
- var iconBandTop = textBlockBottom + height * 0.02f * ss;
- var iconBandBottom = contentBottom - height * 0.11f * ss;
+ var iconBandTop = textBlockBottom + (height * 0.02f * ss);
+ var iconBandBottom = contentBottom - (height * 0.11f * ss);
var iconBandHeight = iconBandBottom - iconBandTop;
var iconWidthTarget = width * 0.68f * ss;
var scaleByWidth = iconWidthTarget / bounds.Width;
@@ -324,7 +324,7 @@ static void RenderPosterLogoFromPicture(string outDir, string fileName, SKPictur
var badgeSize = width * 0.021f * ss;
var badgeBlockHeight = height * 0.088f * ss;
- var badgeRowY = iconTop + scaledHeight + height * 0.02f * ss + (badgeBlockHeight / 2f);
+ var badgeRowY = iconTop + scaledHeight + (height * 0.02f * ss) + (badgeBlockHeight / 2f);
DrawPosterFeatureBadges(canvas, renderWidth, badgeRowY, badgeSize);
DrawPosterPaletteMockup(canvas, renderWidth, renderHeight, contentBottom);
@@ -472,8 +472,8 @@ static void DrawPosterBadgeRow(
static void DrawPosterPaletteMockup(SKCanvas canvas, int width, int height, float contentBottom)
{
- var mockTop = contentBottom + height * 0.018f;
- var mockHeight = height - mockTop - height * 0.035f;
+ var mockTop = contentBottom + (height * 0.018f);
+ var mockHeight = height - mockTop - (height * 0.035f);
var mockWidth = width * 0.86f;
var mockLeft = (width - mockWidth) / 2f;
var corner = mockHeight * 0.07f;
@@ -483,7 +483,7 @@ static void DrawPosterPaletteMockup(SKCanvas canvas, int width, int height, floa
{
IsAntialias = true,
Shader = SKShader.CreateRadialGradient(
- new SKPoint(width * 0.42f, mockTop + mockHeight * 0.55f),
+ new SKPoint(width * 0.42f, mockTop + (mockHeight * 0.55f)),
mockWidth * 0.42f,
new[] { new SKColor(0x2F, 0x96, 0xE8, 0x28), SKColors.Transparent },
null,
@@ -493,7 +493,7 @@ static void DrawPosterPaletteMockup(SKCanvas canvas, int width, int height, floa
{
IsAntialias = true,
Shader = SKShader.CreateRadialGradient(
- new SKPoint(width * 0.62f, mockTop + mockHeight * 0.72f),
+ new SKPoint(width * 0.62f, mockTop + (mockHeight * 0.72f)),
mockWidth * 0.32f,
new[] { new SKColor(0xF0, 0xC0, 0x38, 0x1A), SKColors.Transparent },
null,
@@ -539,15 +539,15 @@ static void DrawPosterPaletteMockup(SKCanvas canvas, int width, int height, floa
TextSize = width * 0.022f,
TextAlign = SKTextAlign.Left,
};
- var chromeX = mockLeft + mockWidth * 0.06f;
+ var chromeX = mockLeft + (mockWidth * 0.06f);
var chromeMetrics = titlePaint.FontMetrics;
- var chromeBaseline = mockTop + titleBarHeight * 0.62f - ((chromeMetrics.Ascent + chromeMetrics.Descent) / 2f);
+ var chromeBaseline = mockTop + (titleBarHeight * 0.62f) - ((chromeMetrics.Ascent + chromeMetrics.Descent) / 2f);
canvas.DrawText("Command Palette", chromeX, chromeBaseline, titlePaint);
- canvas.DrawText("Win+Alt+Space", mockLeft + mockWidth * 0.94f - hintPaint.MeasureText("Win+Alt+Space"), chromeBaseline, hintPaint);
+ canvas.DrawText("Win+Alt+Space", mockLeft + (mockWidth * 0.94f) - hintPaint.MeasureText("Win+Alt+Space"), chromeBaseline, hintPaint);
- var searchTop = mockTop + titleBarHeight + mockHeight * 0.04f;
+ var searchTop = mockTop + titleBarHeight + (mockHeight * 0.04f);
var searchHeight = mockHeight * 0.11f;
- var searchLeft = mockLeft + mockWidth * 0.06f;
+ var searchLeft = mockLeft + (mockWidth * 0.06f);
var searchWidth = mockWidth * 0.88f;
var searchRect = new SKRect(searchLeft, searchTop, searchLeft + searchWidth, searchTop + searchHeight);
using var searchFill = new SKPaint
@@ -576,13 +576,13 @@ static void DrawPosterPaletteMockup(SKCanvas canvas, int width, int height, floa
};
var searchMetrics = searchTextPaint.FontMetrics;
var searchBaseline = searchRect.MidY - ((searchMetrics.Ascent + searchMetrics.Descent) / 2f);
- canvas.DrawText("api", searchLeft + searchWidth * 0.05f, searchBaseline, searchTextPaint);
+ canvas.DrawText("api", searchLeft + (searchWidth * 0.05f), searchBaseline, searchTextPaint);
- var listTop = searchTop + searchHeight + mockHeight * 0.05f;
+ var listTop = searchTop + searchHeight + (mockHeight * 0.05f);
var rowHeight = mockHeight * 0.19f;
DrawPaletteListRow(
canvas,
- mockLeft + mockWidth * 0.06f,
+ mockLeft + (mockWidth * 0.06f),
listTop,
mockWidth * 0.88f,
rowHeight,
@@ -591,8 +591,8 @@ static void DrawPosterPaletteMockup(SKCanvas canvas, int width, int height, floa
selected: true);
DrawPaletteListRow(
canvas,
- mockLeft + mockWidth * 0.06f,
- listTop + rowHeight + mockHeight * 0.02f,
+ mockLeft + (mockWidth * 0.06f),
+ listTop + rowHeight + (mockHeight * 0.02f),
mockWidth * 0.88f,
rowHeight,
"Frontend",
@@ -648,9 +648,9 @@ static void DrawPaletteListRow(
var titleMetrics = titlePaint.FontMetrics;
var subtitleMetrics = subtitlePaint.FontMetrics;
- var textX = left + width * 0.04f;
- var titleBaseline = top + height * 0.38f - ((titleMetrics.Ascent + titleMetrics.Descent) / 2f);
- var subtitleBaseline = top + height * 0.72f - ((subtitleMetrics.Ascent + subtitleMetrics.Descent) / 2f);
+ var textX = left + (width * 0.04f);
+ var titleBaseline = top + (height * 0.38f) - ((titleMetrics.Ascent + titleMetrics.Descent) / 2f);
+ var subtitleBaseline = top + (height * 0.72f) - ((subtitleMetrics.Ascent + subtitleMetrics.Descent) / 2f);
canvas.DrawText(title, textX, titleBaseline, titlePaint);
canvas.DrawText(TruncateToWidth(subtitle, subtitlePaint, width * 0.92f), textX, subtitleBaseline, subtitlePaint);
}