mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
fix.修复了窗口问题,以及多次显示圆角调节选项的问题。
This commit is contained in:
@@ -65,6 +65,22 @@ public sealed class MaterialColorSettingsPageViewModelTests
|
|||||||
Assert.Equal(1, facade.ThemeSaveCount);
|
Assert.Equal(1, facade.ThemeSaveCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void UserSelection_SystemMaterialModeRequestsRestart()
|
||||||
|
{
|
||||||
|
var facade = new FakeSettingsFacade(CreateThemeState(ThemeAppearanceValues.MaterialNone));
|
||||||
|
var materialService = new FakeMaterialColorService(CreateSnapshot(ThemeAppearanceValues.MaterialNone));
|
||||||
|
var viewModel = new MaterialColorSettingsPageViewModel(facade, materialService);
|
||||||
|
string? restartReason = null;
|
||||||
|
viewModel.RestartRequested += reason => restartReason = reason;
|
||||||
|
|
||||||
|
viewModel.SelectedSystemMaterialMode = viewModel.SystemMaterialModes.Single(option =>
|
||||||
|
option.Value == ThemeAppearanceValues.MaterialMica);
|
||||||
|
|
||||||
|
Assert.Equal(viewModel.SystemMaterialRestartMessage, restartReason);
|
||||||
|
Assert.False(string.IsNullOrWhiteSpace(restartReason));
|
||||||
|
}
|
||||||
|
|
||||||
private static ThemeAppearanceSettingsState CreateThemeState(string materialMode)
|
private static ThemeAppearanceSettingsState CreateThemeState(string materialMode)
|
||||||
{
|
{
|
||||||
return new ThemeAppearanceSettingsState(
|
return new ThemeAppearanceSettingsState(
|
||||||
|
|||||||
103
LanMountainDesktop.Tests/SystemChromeModeTests.cs
Normal file
103
LanMountainDesktop.Tests/SystemChromeModeTests.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace LanMountainDesktop.Tests;
|
||||||
|
|
||||||
|
public sealed class SystemChromeModeTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SettingsWindow_SystemChromeUsesNativeDecorations()
|
||||||
|
{
|
||||||
|
var source = ReadRepositoryFile("LanMountainDesktop", "Views", "SettingsWindow.axaml.cs");
|
||||||
|
var applyChromeMode = ExtractMethodSource(source, "ApplyChromeMode");
|
||||||
|
var onLoaded = ExtractMethodSource(source, "OnLoaded");
|
||||||
|
|
||||||
|
Assert.Contains("_useSystemChrome = useSystemChrome || OperatingSystem.IsMacOS();", applyChromeMode);
|
||||||
|
Assert.Contains("WindowDecorations = WindowDecorations.Full;", applyChromeMode);
|
||||||
|
Assert.Contains("ExtendClientAreaToDecorationsHint = !_useSystemChrome;", applyChromeMode);
|
||||||
|
Assert.Contains("ExtendClientAreaTitleBarHeightHint = _useSystemChrome ? 0d : CustomTitleBarHeight;", applyChromeMode);
|
||||||
|
Assert.Contains("TitleBar.ExtendsContentIntoTitleBar = !_useSystemChrome;", applyChromeMode);
|
||||||
|
Assert.Contains("WindowTitleBarHost.IsVisible = false;", applyChromeMode);
|
||||||
|
Assert.Contains("WindowTitleBarHost.IsVisible = true;", applyChromeMode);
|
||||||
|
Assert.DoesNotContain("TitleBar.ExtendsContentIntoTitleBar = true;", onLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ComponentEditorWindow_SystemChromeUsesNativeDecorations()
|
||||||
|
{
|
||||||
|
var source = ReadRepositoryFile("LanMountainDesktop", "Views", "ComponentEditorWindow.axaml.cs");
|
||||||
|
var applyChromeMode = ExtractMethodSource(source, "ApplyChromeMode");
|
||||||
|
|
||||||
|
Assert.Contains("var preferSystemChrome = useSystemChrome || OperatingSystem.IsMacOS();", applyChromeMode);
|
||||||
|
Assert.Contains("WindowDecorations = WindowDecorations.Full;", applyChromeMode);
|
||||||
|
Assert.Contains("ExtendClientAreaToDecorationsHint = false;", applyChromeMode);
|
||||||
|
Assert.Contains("ExtendClientAreaTitleBarHeightHint = 0d;", applyChromeMode);
|
||||||
|
Assert.Contains("CustomTitleBarHost.IsVisible = false;", applyChromeMode);
|
||||||
|
Assert.Contains("WindowDecorations = WindowDecorations.BorderOnly;", applyChromeMode);
|
||||||
|
Assert.Contains("ExtendClientAreaToDecorationsHint = true;", applyChromeMode);
|
||||||
|
Assert.Contains("CustomTitleBarHost.IsVisible = true;", applyChromeMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SavingSystemChromeSynchronizesWindowsPatcherState()
|
||||||
|
{
|
||||||
|
var source = ReadRepositoryFile("LanMountainDesktop", "Services", "Settings", "SettingsDomainServices.cs");
|
||||||
|
|
||||||
|
Assert.Contains("if (OperatingSystem.IsWindows())", source);
|
||||||
|
Assert.Contains("LanMountainDesktop.Platform.Windows.ChromePatchState.UseSystemChrome = state.UseSystemChrome;", source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadRepositoryFile(params string[] segments)
|
||||||
|
{
|
||||||
|
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||||
|
while (directory is not null)
|
||||||
|
{
|
||||||
|
var candidate = Path.Combine(new[] { directory.FullName }.Concat(segments).ToArray());
|
||||||
|
if (File.Exists(candidate))
|
||||||
|
{
|
||||||
|
return File.ReadAllText(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(directory.FullName, "LanMountainDesktop.slnx")))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
directory = directory.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileNotFoundException($"Could not locate repository file '{Path.Combine(segments)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExtractMethodSource(string source, string methodName)
|
||||||
|
{
|
||||||
|
var methodIndex = source.IndexOf($"private void {methodName}(", StringComparison.Ordinal);
|
||||||
|
if (methodIndex < 0)
|
||||||
|
{
|
||||||
|
methodIndex = source.IndexOf($"public void {methodName}(", StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.True(methodIndex >= 0, $"Could not locate method '{methodName}'.");
|
||||||
|
|
||||||
|
var braceIndex = source.IndexOf('{', methodIndex);
|
||||||
|
Assert.True(braceIndex >= 0, $"Could not locate method body for '{methodName}'.");
|
||||||
|
|
||||||
|
var depth = 0;
|
||||||
|
for (var i = braceIndex; i < source.Length; i++)
|
||||||
|
{
|
||||||
|
if (source[i] == '{')
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
else if (source[i] == '}')
|
||||||
|
{
|
||||||
|
depth--;
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
return source.Substring(methodIndex, i - methodIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException($"Could not extract method '{methodName}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -394,8 +394,6 @@
|
|||||||
"settings.appearance.theme_color_preview.app": "Currently previewing colors extracted from the app wallpaper.",
|
"settings.appearance.theme_color_preview.app": "Currently previewing colors extracted from the app wallpaper.",
|
||||||
"settings.appearance.theme_color_preview.system": "Currently previewing colors extracted from the system wallpaper.",
|
"settings.appearance.theme_color_preview.system": "Currently previewing colors extracted from the system wallpaper.",
|
||||||
"settings.appearance.theme_color_preview.fallback": "No usable wallpaper was found. The app is using a fallback accent.",
|
"settings.appearance.theme_color_preview.fallback": "No usable wallpaper was found. The app is using a fallback accent.",
|
||||||
"settings.appearance.corner_radius.label": "Global corner radius style",
|
|
||||||
"settings.appearance.corner_radius.description": "Select a fixed corner radius style inspired by Xiaomi HyperOS.",
|
|
||||||
"component.color_scheme.follow_system": "Follow system color scheme",
|
"component.color_scheme.follow_system": "Follow system color scheme",
|
||||||
"component.color_scheme.native": "Use component custom color scheme",
|
"component.color_scheme.native": "Use component custom color scheme",
|
||||||
"component.settings.color_scheme": "Color Scheme",
|
"component.settings.color_scheme": "Color Scheme",
|
||||||
@@ -406,7 +404,7 @@
|
|||||||
"settings.appearance.system_material_desc.switchable": "Apply the selected material to windows, Dock, status bar, and component hosts.",
|
"settings.appearance.system_material_desc.switchable": "Apply the selected material to windows, Dock, status bar, and component hosts.",
|
||||||
"settings.appearance.system_material_desc.fixed": "Your current system only exposes the material modes listed here.",
|
"settings.appearance.system_material_desc.fixed": "Your current system only exposes the material modes listed here.",
|
||||||
"settings.appearance.system_material_desc.auto": "Auto prefers Mica on Windows 11, Acrylic on Windows 10, and falls back to no material when unavailable.",
|
"settings.appearance.system_material_desc.auto": "Auto prefers Mica on Windows 11, Acrylic on Windows 10, and falls back to no material when unavailable.",
|
||||||
"settings.appearance.restart_message": "Theme source and system material changes require restarting the app.",
|
"settings.appearance.restart_message": "Window chrome changes require restarting the app.",
|
||||||
"settings.appearance.preview.primary": "Primary",
|
"settings.appearance.preview.primary": "Primary",
|
||||||
"settings.appearance.preview.secondary": "Secondary",
|
"settings.appearance.preview.secondary": "Secondary",
|
||||||
"settings.appearance.preview.tertiary": "Tertiary",
|
"settings.appearance.preview.tertiary": "Tertiary",
|
||||||
@@ -442,6 +440,7 @@
|
|||||||
"settings.material_color.wallpaper_seed.label": "Seed",
|
"settings.material_color.wallpaper_seed.label": "Seed",
|
||||||
"settings.material_color.system_material.label": "System material",
|
"settings.material_color.system_material.label": "System material",
|
||||||
"settings.material_color.system_material.description": "Apply the selected material mode to windows and host surfaces.",
|
"settings.material_color.system_material.description": "Apply the selected material mode to windows and host surfaces.",
|
||||||
|
"settings.material_color.system_material.restart_message": "System material changes require restarting the app.",
|
||||||
"settings.material_color.native_events.label": "Native wallpaper change events",
|
"settings.material_color.native_events.label": "Native wallpaper change events",
|
||||||
"settings.material_color.native_events.description": "Use OS wallpaper notifications first and keep polling as fallback.",
|
"settings.material_color.native_events.description": "Use OS wallpaper notifications first and keep polling as fallback.",
|
||||||
"settings.material_color.native_events.active": "Native wallpaper events active",
|
"settings.material_color.native_events.active": "Native wallpaper events active",
|
||||||
|
|||||||
@@ -394,8 +394,6 @@
|
|||||||
"settings.appearance.theme_color_preview.app": "当前正在预览从应用壁纸提取的颜色。",
|
"settings.appearance.theme_color_preview.app": "当前正在预览从应用壁纸提取的颜色。",
|
||||||
"settings.appearance.theme_color_preview.system": "当前正在预览从系统壁纸提取的颜色。",
|
"settings.appearance.theme_color_preview.system": "当前正在预览从系统壁纸提取的颜色。",
|
||||||
"settings.appearance.theme_color_preview.fallback": "没有可用壁纸,当前使用回退强调色。",
|
"settings.appearance.theme_color_preview.fallback": "没有可用壁纸,当前使用回退强调色。",
|
||||||
"settings.appearance.corner_radius.label": "全局圆角样式",
|
|
||||||
"settings.appearance.corner_radius.description": "选择固定的全局圆角样式,受 HyperOS 启发。",
|
|
||||||
"component.color_scheme.follow_system": "跟随系统配色",
|
"component.color_scheme.follow_system": "跟随系统配色",
|
||||||
"component.color_scheme.native": "使用组件自定义配色",
|
"component.color_scheme.native": "使用组件自定义配色",
|
||||||
"component.settings.color_scheme": "配色方案",
|
"component.settings.color_scheme": "配色方案",
|
||||||
@@ -406,7 +404,7 @@
|
|||||||
"settings.appearance.system_material_desc.switchable": "将所选材质应用到窗口、Dock、状态栏和组件宿主背板。",
|
"settings.appearance.system_material_desc.switchable": "将所选材质应用到窗口、Dock、状态栏和组件宿主背板。",
|
||||||
"settings.appearance.system_material_desc.fixed": "当前系统仅提供这里列出的材质模式。",
|
"settings.appearance.system_material_desc.fixed": "当前系统仅提供这里列出的材质模式。",
|
||||||
"settings.appearance.system_material_desc.auto": "自动模式会在 Windows 11 优先使用 Mica,在 Windows 10 优先使用 Acrylic,不可用时回退到无材质。",
|
"settings.appearance.system_material_desc.auto": "自动模式会在 Windows 11 优先使用 Mica,在 Windows 10 优先使用 Acrylic,不可用时回退到无材质。",
|
||||||
"settings.appearance.restart_message": "主题色来源和系统材质更改需要重启应用。",
|
"settings.appearance.restart_message": "窗口边框模式更改需要重启应用。",
|
||||||
"settings.appearance.preview.primary": "主色",
|
"settings.appearance.preview.primary": "主色",
|
||||||
"settings.appearance.preview.secondary": "次色",
|
"settings.appearance.preview.secondary": "次色",
|
||||||
"settings.appearance.preview.tertiary": "三次色",
|
"settings.appearance.preview.tertiary": "三次色",
|
||||||
@@ -442,6 +440,7 @@
|
|||||||
"settings.material_color.wallpaper_seed.label": "种子色",
|
"settings.material_color.wallpaper_seed.label": "种子色",
|
||||||
"settings.material_color.system_material.label": "系统材质",
|
"settings.material_color.system_material.label": "系统材质",
|
||||||
"settings.material_color.system_material.description": "将所选材质模式应用到窗口和宿主表面。",
|
"settings.material_color.system_material.description": "将所选材质模式应用到窗口和宿主表面。",
|
||||||
|
"settings.material_color.system_material.restart_message": "系统材质更改需要重启应用。",
|
||||||
"settings.material_color.native_events.label": "原生壁纸变更事件",
|
"settings.material_color.native_events.label": "原生壁纸变更事件",
|
||||||
"settings.material_color.native_events.description": "优先使用操作系统壁纸通知,并保持轮询作为回退。",
|
"settings.material_color.native_events.description": "优先使用操作系统壁纸通知,并保持轮询作为回退。",
|
||||||
"settings.material_color.native_events.active": "原生壁纸事件已激活",
|
"settings.material_color.native_events.active": "原生壁纸事件已激活",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public static class PendingRestartStateService
|
|||||||
public const string RenderModeReason = "RenderMode";
|
public const string RenderModeReason = "RenderMode";
|
||||||
public const string PluginCatalogReason = "PluginCatalog";
|
public const string PluginCatalogReason = "PluginCatalog";
|
||||||
public const string SettingsWindowReason = "SettingsWindow";
|
public const string SettingsWindowReason = "SettingsWindow";
|
||||||
|
public const string SystemMaterialReason = "SystemMaterial";
|
||||||
|
|
||||||
private static readonly object Gate = new();
|
private static readonly object Gate = new();
|
||||||
private static readonly HashSet<string> PendingReasons = new(StringComparer.OrdinalIgnoreCase);
|
private static readonly HashSet<string> PendingReasons = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|||||||
@@ -315,6 +315,10 @@ internal sealed class ThemeAppearanceService : IThemeAppearanceService
|
|||||||
{
|
{
|
||||||
snapshot.UseSystemChrome = state.UseSystemChrome;
|
snapshot.UseSystemChrome = state.UseSystemChrome;
|
||||||
changedKeys.Add(nameof(AppSettingsSnapshot.UseSystemChrome));
|
changedKeys.Add(nameof(AppSettingsSnapshot.UseSystemChrome));
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
LanMountainDesktop.Platform.Windows.ChromePatchState.UseSystemChrome = state.UseSystemChrome;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.Equals(GlobalAppearanceSettings.NormalizeCornerRadiusStyle(snapshot.CornerRadiusStyle), normalizedCornerRadiusStyle, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(GlobalAppearanceSettings.NormalizeCornerRadiusStyle(snapshot.CornerRadiusStyle), normalizedCornerRadiusStyle, StringComparison.OrdinalIgnoreCase))
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ internal sealed class SettingsWindowService : ISettingsWindowService
|
|||||||
? ThemeVariant.Dark
|
? ThemeVariant.Dark
|
||||||
: ThemeVariant.Light;
|
: ThemeVariant.Light;
|
||||||
appearanceThemeService.ApplyThemeResources(window.Resources);
|
appearanceThemeService.ApplyThemeResources(window.Resources);
|
||||||
|
window.ApplyFluentCornerRadius();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyThemeVariantAndResources(SettingsWindow window)
|
private void ApplyThemeVariantAndResources(SettingsWindow window)
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ public sealed partial class MaterialColorSettingsPageViewModel : ViewModelBase
|
|||||||
_materialColorService.MaterialColorChanged += OnMaterialColorChanged;
|
_materialColorService.MaterialColorChanged += OnMaterialColorChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event Action<string>? RestartRequested;
|
||||||
|
|
||||||
public IReadOnlyList<SelectionOption> ColorModes { get; }
|
public IReadOnlyList<SelectionOption> ColorModes { get; }
|
||||||
|
|
||||||
public IReadOnlyList<SelectionOption> WallpaperColorSources { get; }
|
public IReadOnlyList<SelectionOption> WallpaperColorSources { get; }
|
||||||
@@ -176,6 +178,9 @@ public sealed partial class MaterialColorSettingsPageViewModel : ViewModelBase
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _systemMaterialDescription = string.Empty;
|
private string _systemMaterialDescription = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _systemMaterialRestartMessage = string.Empty;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _nativeWallpaperEventsLabel = string.Empty;
|
private string _nativeWallpaperEventsLabel = string.Empty;
|
||||||
|
|
||||||
@@ -313,7 +318,14 @@ public sealed partial class MaterialColorSettingsPageViewModel : ViewModelBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var currentMode = ThemeAppearanceValues.NormalizeSystemMaterialMode(_settingsFacade.Theme.Get().SystemMaterialMode);
|
||||||
|
var requestedMode = ThemeAppearanceValues.NormalizeSystemMaterialMode(value.Value);
|
||||||
SaveTheme();
|
SaveTheme();
|
||||||
|
if (!string.Equals(currentMode, requestedMode, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
PendingRestartStateService.SetPending(PendingRestartStateService.SystemMaterialReason, true);
|
||||||
|
RestartRequested?.Invoke(SystemMaterialRestartMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnSelectedRefreshIntervalChanged(SelectionOption value)
|
partial void OnSelectedRefreshIntervalChanged(SelectionOption value)
|
||||||
@@ -577,6 +589,9 @@ public sealed partial class MaterialColorSettingsPageViewModel : ViewModelBase
|
|||||||
WallpaperSeedLabel = L("settings.material_color.wallpaper_seed.label", "Seed");
|
WallpaperSeedLabel = L("settings.material_color.wallpaper_seed.label", "Seed");
|
||||||
SystemMaterialLabel = L("settings.material_color.system_material.label", "System material");
|
SystemMaterialLabel = L("settings.material_color.system_material.label", "System material");
|
||||||
SystemMaterialDescription = L("settings.material_color.system_material.description", "Apply the selected material mode to windows and host surfaces.");
|
SystemMaterialDescription = L("settings.material_color.system_material.description", "Apply the selected material mode to windows and host surfaces.");
|
||||||
|
SystemMaterialRestartMessage = L(
|
||||||
|
"settings.material_color.system_material.restart_message",
|
||||||
|
"System material changes require restarting the app.");
|
||||||
NativeWallpaperEventsLabel = L("settings.material_color.native_events.label", "Native wallpaper change events");
|
NativeWallpaperEventsLabel = L("settings.material_color.native_events.label", "Native wallpaper change events");
|
||||||
NativeWallpaperEventsDescription = L("settings.material_color.native_events.description", "Use OS wallpaper notifications first and keep polling as fallback.");
|
NativeWallpaperEventsDescription = L("settings.material_color.native_events.description", "Use OS wallpaper notifications first and keep polling as fallback.");
|
||||||
RefreshIntervalLabel = L("settings.material_color.refresh_interval.label", "Polling interval");
|
RefreshIntervalLabel = L("settings.material_color.refresh_interval.label", "Polling interval");
|
||||||
|
|||||||
@@ -1032,27 +1032,12 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _useSystemChromeLabel = string.Empty;
|
private string _useSystemChromeLabel = string.Empty;
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private string _cornerRadiusStyleLabel = string.Empty;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private string _cornerRadiusStyleDescription = string.Empty;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _themeHeader = string.Empty;
|
private string _themeHeader = string.Empty;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _appearanceRestartMessage = string.Empty;
|
private string _appearanceRestartMessage = string.Empty;
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private string _cornerRadiusStyle = GlobalAppearanceSettings.DefaultCornerRadiusStyle;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private IReadOnlyList<SelectionOption> _cornerRadiusStyleOptions = [];
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private SelectionOption? _selectedCornerRadiusStyle;
|
|
||||||
|
|
||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
var theme = _settingsFacade.Theme.Get();
|
var theme = _settingsFacade.Theme.Get();
|
||||||
@@ -1101,17 +1086,6 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
|||||||
PersistCurrentState(restartRequired: true);
|
PersistCurrentState(restartRequired: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnSelectedCornerRadiusStyleChanged(SelectionOption? value)
|
|
||||||
{
|
|
||||||
if (_isInitializing || value is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CornerRadiusStyle = value.Value;
|
|
||||||
PersistCurrentState(restartRequired: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RefreshLocalizedText()
|
private void RefreshLocalizedText()
|
||||||
{
|
{
|
||||||
ThemeHeader = L("settings.appearance.theme_header", "Theme");
|
ThemeHeader = L("settings.appearance.theme_header", "Theme");
|
||||||
@@ -1121,25 +1095,15 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
|||||||
ThemeModeDarkText = L("settings.appearance.theme_mode.dark", "Dark");
|
ThemeModeDarkText = L("settings.appearance.theme_mode.dark", "Dark");
|
||||||
ThemeModeFollowSystemText = L("settings.appearance.theme_mode.follow_system", "Follow system");
|
ThemeModeFollowSystemText = L("settings.appearance.theme_mode.follow_system", "Follow system");
|
||||||
UseSystemChromeLabel = L("settings.color.use_system_chrome_toggle", "Use system window chrome");
|
UseSystemChromeLabel = L("settings.color.use_system_chrome_toggle", "Use system window chrome");
|
||||||
CornerRadiusStyleLabel = L("settings.appearance.corner_radius.label", "Global corner radius style");
|
|
||||||
CornerRadiusStyleDescription = L("settings.appearance.corner_radius.description", "Select a fixed corner radius style inspired by Xiaomi HyperOS.");
|
|
||||||
AppearanceRestartMessage = L(
|
AppearanceRestartMessage = L(
|
||||||
"settings.appearance.restart_message",
|
"settings.appearance.restart_message",
|
||||||
"Window chrome changes require restarting the app.");
|
"Window chrome changes require restarting the app.");
|
||||||
|
|
||||||
CornerRadiusStyleOptions = GlobalAppearanceSettings.AllCornerRadiusStyles
|
|
||||||
.Select(style => new SelectionOption(style, L($"settings.appearance.corner_radius.style_{style.ToLower()}", style)))
|
|
||||||
.ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplySavedState(ThemeAppearanceSettingsState theme)
|
private void ApplySavedState(ThemeAppearanceSettingsState theme)
|
||||||
{
|
{
|
||||||
IsNightMode = theme.IsNightMode;
|
IsNightMode = theme.IsNightMode;
|
||||||
UseSystemChrome = theme.UseSystemChrome;
|
UseSystemChrome = theme.UseSystemChrome;
|
||||||
CornerRadiusStyle = GlobalAppearanceSettings.NormalizeCornerRadiusStyle(theme.CornerRadiusStyle);
|
|
||||||
SelectedCornerRadiusStyle = CornerRadiusStyleOptions.FirstOrDefault(option =>
|
|
||||||
string.Equals(option.Value, CornerRadiusStyle, StringComparison.OrdinalIgnoreCase))
|
|
||||||
?? CornerRadiusStyleOptions.FirstOrDefault(o => o.Value == GlobalAppearanceSettings.DefaultCornerRadiusStyle);
|
|
||||||
|
|
||||||
var savedThemeMode = NormalizeThemeMode(theme.ThemeMode);
|
var savedThemeMode = NormalizeThemeMode(theme.ThemeMode);
|
||||||
SelectedThemeMode = ThemeModeOptions.FirstOrDefault(option =>
|
SelectedThemeMode = ThemeModeOptions.FirstOrDefault(option =>
|
||||||
@@ -1201,7 +1165,6 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
IsNightMode = IsNightMode,
|
IsNightMode = IsNightMode,
|
||||||
UseSystemChrome = UseSystemChrome,
|
UseSystemChrome = UseSystemChrome,
|
||||||
CornerRadiusStyle = GlobalAppearanceSettings.NormalizeCornerRadiusStyle(CornerRadiusStyle),
|
|
||||||
ThemeMode = SelectedThemeMode?.Value ?? ThemeAppearanceValues.ThemeModeLight
|
ThemeMode = SelectedThemeMode?.Value ?? ThemeAppearanceValues.ThemeModeLight
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,14 +59,16 @@ public partial class ComponentEditorWindow : Window
|
|||||||
var preferSystemChrome = useSystemChrome || OperatingSystem.IsMacOS();
|
var preferSystemChrome = useSystemChrome || OperatingSystem.IsMacOS();
|
||||||
if (preferSystemChrome)
|
if (preferSystemChrome)
|
||||||
{
|
{
|
||||||
ExtendClientAreaToDecorationsHint = true;
|
|
||||||
WindowDecorations = WindowDecorations.Full;
|
WindowDecorations = WindowDecorations.Full;
|
||||||
|
ExtendClientAreaToDecorationsHint = false;
|
||||||
|
ExtendClientAreaTitleBarHeightHint = 0d;
|
||||||
CustomTitleBarHost.IsVisible = false;
|
CustomTitleBarHost.IsVisible = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowDecorations = WindowDecorations.BorderOnly;
|
WindowDecorations = WindowDecorations.BorderOnly;
|
||||||
ExtendClientAreaToDecorationsHint = true;
|
ExtendClientAreaToDecorationsHint = true;
|
||||||
|
ExtendClientAreaTitleBarHeightHint = 0d;
|
||||||
CustomTitleBarHost.IsVisible = true;
|
CustomTitleBarHost.IsVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,23 +38,6 @@
|
|||||||
</ui:FASettingsExpander.Footer>
|
</ui:FASettingsExpander.Footer>
|
||||||
</ui:FASettingsExpander>
|
</ui:FASettingsExpander>
|
||||||
|
|
||||||
<ui:FASettingsExpander Header="{Binding CornerRadiusStyleLabel}"
|
|
||||||
Description="{Binding CornerRadiusStyleDescription}">
|
|
||||||
<ui:FASettingsExpander.IconSource>
|
|
||||||
<ui:FAFontIconSource Glyph="󰄦" FontFamily="avares://fluenticons.resources.avalonia/Assets#Seagull Fluent Icons" />
|
|
||||||
</ui:FASettingsExpander.IconSource>
|
|
||||||
<ui:FASettingsExpander.Footer>
|
|
||||||
<ComboBox Width="220"
|
|
||||||
ItemsSource="{Binding CornerRadiusStyleOptions}"
|
|
||||||
SelectedItem="{Binding SelectedCornerRadiusStyle}">
|
|
||||||
<ComboBox.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="vm:SelectionOption">
|
|
||||||
<TextBlock Text="{Binding Label}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ComboBox.ItemTemplate>
|
|
||||||
</ComboBox>
|
|
||||||
</ui:FASettingsExpander.Footer>
|
|
||||||
</ui:FASettingsExpander>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -27,12 +27,18 @@ public partial class MaterialColorSettingsPage : SettingsPageBase
|
|||||||
public MaterialColorSettingsPage(MaterialColorSettingsPageViewModel viewModel)
|
public MaterialColorSettingsPage(MaterialColorSettingsPageViewModel viewModel)
|
||||||
{
|
{
|
||||||
ViewModel = viewModel;
|
ViewModel = viewModel;
|
||||||
|
ViewModel.RestartRequested += OnRestartRequested;
|
||||||
DataContext = ViewModel;
|
DataContext = ViewModel;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MaterialColorSettingsPageViewModel ViewModel { get; }
|
public MaterialColorSettingsPageViewModel ViewModel { get; }
|
||||||
|
|
||||||
|
private void OnRestartRequested(string reason)
|
||||||
|
{
|
||||||
|
RequestRestart(reason);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnWallpaperSeedCandidateClick(object? sender, RoutedEventArgs e)
|
private void OnWallpaperSeedCandidateClick(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_ = e;
|
_ = e;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ using LanMountainDesktop.PluginSdk;
|
|||||||
using LanMountainDesktop.Services;
|
using LanMountainDesktop.Services;
|
||||||
using LanMountainDesktop.Services.Settings;
|
using LanMountainDesktop.Services.Settings;
|
||||||
using LanMountainDesktop.Settings.Core;
|
using LanMountainDesktop.Settings.Core;
|
||||||
|
using LanMountainDesktop.Shared.Contracts;
|
||||||
using LanMountainDesktop.ViewModels;
|
using LanMountainDesktop.ViewModels;
|
||||||
using Symbol = FluentIcons.Common.Symbol;
|
using Symbol = FluentIcons.Common.Symbol;
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
|
|||||||
private const double MinPaneOpenLength = 260d;
|
private const double MinPaneOpenLength = 260d;
|
||||||
private const double MaxPaneOpenLength = 288d;
|
private const double MaxPaneOpenLength = 288d;
|
||||||
private const double BaseNarrowThreshold = 800d;
|
private const double BaseNarrowThreshold = 800d;
|
||||||
|
private const double CustomTitleBarHeight = 48d;
|
||||||
private const string PaneToggleItemTag = "__pane_toggle__";
|
private const string PaneToggleItemTag = "__pane_toggle__";
|
||||||
|
|
||||||
private readonly ISettingsPageRegistry _pageRegistry;
|
private readonly ISettingsPageRegistry _pageRegistry;
|
||||||
@@ -89,14 +91,14 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
|
|||||||
|
|
||||||
private void OnLoaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
private void OnLoaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
TitleBar.Height = 48;
|
TitleBar.Height = CustomTitleBarHeight;
|
||||||
TitleBar.ExtendsContentIntoTitleBar = true;
|
|
||||||
|
|
||||||
// SecRandom MainWindow:标题栏按钮悬停/按下/非活动色,与系统 caption 更一致
|
// Match the native caption button feedback used by SecRandom MainWindow.
|
||||||
TitleBar.ButtonHoverBackgroundColor = Color.FromArgb(23, 0, 0, 0);
|
TitleBar.ButtonHoverBackgroundColor = Color.FromArgb(23, 0, 0, 0);
|
||||||
TitleBar.ButtonPressedBackgroundColor = Color.FromArgb(52, 0, 0, 0);
|
TitleBar.ButtonPressedBackgroundColor = Color.FromArgb(52, 0, 0, 0);
|
||||||
TitleBar.ButtonInactiveForegroundColor = Colors.Gray;
|
TitleBar.ButtonInactiveForegroundColor = Colors.Gray;
|
||||||
|
|
||||||
|
ApplyChromeMode(_useSystemChrome);
|
||||||
SyncPendingRestartState();
|
SyncPendingRestartState();
|
||||||
SyncTitleText();
|
SyncTitleText();
|
||||||
UpdateChromeMetrics();
|
UpdateChromeMetrics();
|
||||||
@@ -186,8 +188,11 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
|
|||||||
{
|
{
|
||||||
_useSystemChrome = useSystemChrome || OperatingSystem.IsMacOS();
|
_useSystemChrome = useSystemChrome || OperatingSystem.IsMacOS();
|
||||||
|
|
||||||
ExtendClientAreaToDecorationsHint = true;
|
|
||||||
WindowDecorations = WindowDecorations.Full;
|
WindowDecorations = WindowDecorations.Full;
|
||||||
|
ExtendClientAreaToDecorationsHint = !_useSystemChrome;
|
||||||
|
ExtendClientAreaTitleBarHeightHint = _useSystemChrome ? 0d : CustomTitleBarHeight;
|
||||||
|
TitleBar.ExtendsContentIntoTitleBar = !_useSystemChrome;
|
||||||
|
TitleBar.Height = CustomTitleBarHeight;
|
||||||
|
|
||||||
if (_useSystemChrome)
|
if (_useSystemChrome)
|
||||||
{
|
{
|
||||||
@@ -564,6 +569,7 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
|
|||||||
CloseButtonText = ViewModel.RestartDialogCloseText,
|
CloseButtonText = ViewModel.RestartDialogCloseText,
|
||||||
DefaultButton = FAContentDialogButton.Primary
|
DefaultButton = FAContentDialogButton.Primary
|
||||||
};
|
};
|
||||||
|
ApplyFluentCornerRadius(dialog.Resources);
|
||||||
|
|
||||||
var result = await dialog.ShowAsync(this);
|
var result = await dialog.ShowAsync(this);
|
||||||
if (result == FAContentDialogResult.Primary)
|
if (result == FAContentDialogResult.Primary)
|
||||||
@@ -802,27 +808,40 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Override global corner radius tokens on the settings window root grid
|
/// Override inherited corner radius tokens on the settings window root grid
|
||||||
/// so all child controls use Microsoft Fluent Design System values,
|
/// so all child controls use Microsoft Fluent Design System values,
|
||||||
/// independent of the user's global corner radius preference.
|
/// independent of the user's component corner radius preference.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void ApplyFluentCornerRadius()
|
public void ApplyFluentCornerRadius()
|
||||||
{
|
{
|
||||||
if (RootGrid is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokens = AppearanceCornerRadiusTokenFactory.Create(
|
var tokens = AppearanceCornerRadiusTokenFactory.Create(
|
||||||
GlobalAppearanceSettings.CornerRadiusStyleFluent);
|
GlobalAppearanceSettings.CornerRadiusStyleFluent);
|
||||||
RootGrid.Resources["DesignCornerRadiusMicro"] = tokens.Micro;
|
ApplyFluentCornerRadius(Resources, tokens);
|
||||||
RootGrid.Resources["DesignCornerRadiusXs"] = tokens.Xs;
|
if (RootGrid is not null)
|
||||||
RootGrid.Resources["DesignCornerRadiusSm"] = tokens.Sm;
|
{
|
||||||
RootGrid.Resources["DesignCornerRadiusMd"] = tokens.Md;
|
ApplyFluentCornerRadius(RootGrid.Resources, tokens);
|
||||||
RootGrid.Resources["DesignCornerRadiusLg"] = tokens.Lg;
|
}
|
||||||
RootGrid.Resources["DesignCornerRadiusXl"] = tokens.Xl;
|
}
|
||||||
RootGrid.Resources["DesignCornerRadiusIsland"] = tokens.Island;
|
|
||||||
RootGrid.Resources["DesignCornerRadiusComponent"] = tokens.Component;
|
private static void ApplyFluentCornerRadius(IResourceDictionary resources)
|
||||||
|
{
|
||||||
|
var tokens = AppearanceCornerRadiusTokenFactory.Create(
|
||||||
|
GlobalAppearanceSettings.CornerRadiusStyleFluent);
|
||||||
|
ApplyFluentCornerRadius(resources, tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyFluentCornerRadius(
|
||||||
|
IResourceDictionary resources,
|
||||||
|
AppearanceCornerRadiusTokens tokens)
|
||||||
|
{
|
||||||
|
resources["DesignCornerRadiusMicro"] = tokens.Micro;
|
||||||
|
resources["DesignCornerRadiusXs"] = tokens.Xs;
|
||||||
|
resources["DesignCornerRadiusSm"] = tokens.Sm;
|
||||||
|
resources["DesignCornerRadiusMd"] = tokens.Md;
|
||||||
|
resources["DesignCornerRadiusLg"] = tokens.Lg;
|
||||||
|
resources["DesignCornerRadiusXl"] = tokens.Xl;
|
||||||
|
resources["DesignCornerRadiusIsland"] = tokens.Island;
|
||||||
|
resources["DesignCornerRadiusComponent"] = tokens.Component;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTitleBarDragZonePointerPressed(object? sender, PointerPressedEventArgs e)
|
private void OnTitleBarDragZonePointerPressed(object? sender, PointerPressedEventArgs e)
|
||||||
@@ -973,7 +992,7 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
|
|||||||
var height = Bounds.Height > 1 ? Bounds.Height : Math.Max(Height, MinHeight);
|
var height = Bounds.Height > 1 ? Bounds.Height : Math.Max(Height, MinHeight);
|
||||||
var layoutScale = Math.Clamp(Math.Min(width / 1120d, height / 760d), 0.90, 1.18);
|
var layoutScale = Math.Clamp(Math.Min(width / 1120d, height / 760d), 0.90, 1.18);
|
||||||
|
|
||||||
const double titleBarHeight = 48d;
|
const double titleBarHeight = CustomTitleBarHeight;
|
||||||
var titleFontSize = Math.Clamp(12d * layoutScale, 11d, 14d);
|
var titleFontSize = Math.Clamp(12d * layoutScale, 11d, 14d);
|
||||||
var titleBarIconSize = Math.Clamp(16d * layoutScale, 15d, 20d);
|
var titleBarIconSize = Math.Clamp(16d * layoutScale, 15d, 20d);
|
||||||
var drawerTitleFontSize = Math.Clamp(16d * layoutScale, 14d, 20d);
|
var drawerTitleFontSize = Math.Clamp(16d * layoutScale, 14d, 20d);
|
||||||
|
|||||||
@@ -107,3 +107,327 @@
|
|||||||
|
|
||||||
MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS
|
MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS
|
||||||
|
|
||||||
|
|
||||||
|
SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS
|
||||||
|
|
||||||
|
Commands marked with * may be preceded by a number, _N.
|
||||||
|
Notes in parentheses indicate the behavior if _N is given.
|
||||||
|
A key preceded by a caret indicates the Ctrl key; thus ^K is ctrl-K.
|
||||||
|
|
||||||
|
h H Display this help.
|
||||||
|
q :q Q :Q ZZ Exit.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
MMOOVVIINNGG
|
||||||
|
|
||||||
|
e ^E j ^N CR * Forward one line (or _N lines).
|
||||||
|
y ^Y k ^K ^P * Backward one line (or _N lines).
|
||||||
|
ESC-j * Forward one file line (or _N file lines).
|
||||||
|
ESC-k * Backward one file line (or _N file lines).
|
||||||
|
f ^F ^V SPACE * Forward one window (or _N lines).
|
||||||
|
b ^B ESC-v * Backward one window (or _N lines).
|
||||||
|
z * Forward one window (and set window to _N).
|
||||||
|
w * Backward one window (and set window to _N).
|
||||||
|
ESC-SPACE * Forward one window, but don't stop at end-of-file.
|
||||||
|
ESC-b * Backward one window, but don't stop at beginning-of-file.
|
||||||
|
d ^D * Forward one half-window (and set half-window to _N).
|
||||||
|
u ^U * Backward one half-window (and set half-window to _N).
|
||||||
|
ESC-) RightArrow * Right one half screen width (or _N positions).
|
||||||
|
ESC-( LeftArrow * Left one half screen width (or _N positions).
|
||||||
|
ESC-} ^RightArrow Right to last column displayed.
|
||||||
|
ESC-{ ^LeftArrow Left to first column.
|
||||||
|
F Forward forever; like "tail -f".
|
||||||
|
ESC-F Like F but stop when search pattern is found.
|
||||||
|
r ^R ^L Repaint screen.
|
||||||
|
R Repaint screen, discarding buffered input.
|
||||||
|
---------------------------------------------------
|
||||||
|
Default "window" is the screen height.
|
||||||
|
Default "half-window" is half of the screen height.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SSEEAARRCCHHIINNGG
|
||||||
|
|
||||||
|
/_p_a_t_t_e_r_n * Search forward for (_N-th) matching line.
|
||||||
|
?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line.
|
||||||
|
n * Repeat previous search (for _N-th occurrence).
|
||||||
|
N * Repeat previous search in reverse direction.
|
||||||
|
ESC-n * Repeat previous search, spanning files.
|
||||||
|
ESC-N * Repeat previous search, reverse dir. & spanning files.
|
||||||
|
^O^N ^On * Search forward for (_N-th) OSC8 hyperlink.
|
||||||
|
^O^P ^Op * Search backward for (_N-th) OSC8 hyperlink.
|
||||||
|
^O^L ^Ol Jump to the currently selected OSC8 hyperlink.
|
||||||
|
ESC-u Undo (toggle) search highlighting.
|
||||||
|
ESC-U Clear search highlighting.
|
||||||
|
&_p_a_t_t_e_r_n * Display only matching lines.
|
||||||
|
---------------------------------------------------
|
||||||
|
Search is case-sensitive unless changed with -i or -I.
|
||||||
|
A search pattern may begin with one or more of:
|
||||||
|
^N or ! Search for NON-matching lines.
|
||||||
|
^E or * Search multiple files (pass thru END OF FILE).
|
||||||
|
^F or @ Start search at FIRST file (for /) or last file (for ?).
|
||||||
|
^K Highlight matches, but don't move (KEEP position).
|
||||||
|
^R Don't use REGULAR EXPRESSIONS.
|
||||||
|
^S _n Search for match in _n-th parenthesized subpattern.
|
||||||
|
^W WRAP search if no match found.
|
||||||
|
^L Enter next character literally into pattern.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
JJUUMMPPIINNGG
|
||||||
|
|
||||||
|
g < ESC-< * Go to first line in file (or line _N).
|
||||||
|
G > ESC-> * Go to last line in file (or line _N).
|
||||||
|
p % * Go to beginning of file (or _N percent into file).
|
||||||
|
t * Go to the (_N-th) next tag.
|
||||||
|
T * Go to the (_N-th) previous tag.
|
||||||
|
{ ( [ * Find close bracket } ) ].
|
||||||
|
} ) ] * Find open bracket { ( [.
|
||||||
|
ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>.
|
||||||
|
ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>.
|
||||||
|
---------------------------------------------------
|
||||||
|
Each "find close bracket" command goes forward to the close bracket
|
||||||
|
matching the (_N-th) open bracket in the top line.
|
||||||
|
Each "find open bracket" command goes backward to the open bracket
|
||||||
|
matching the (_N-th) close bracket in the bottom line.
|
||||||
|
|
||||||
|
m_<_l_e_t_t_e_r_> Mark the current top line with <letter>.
|
||||||
|
M_<_l_e_t_t_e_r_> Mark the current bottom line with <letter>.
|
||||||
|
'_<_l_e_t_t_e_r_> Go to a previously marked position.
|
||||||
|
'' Go to the previous position.
|
||||||
|
^X^X Same as '.
|
||||||
|
ESC-m_<_l_e_t_t_e_r_> Clear a mark.
|
||||||
|
---------------------------------------------------
|
||||||
|
A mark is any upper-case or lower-case letter.
|
||||||
|
Certain marks are predefined:
|
||||||
|
^ means beginning of the file
|
||||||
|
$ means end of the file
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CCHHAANNGGIINNGG FFIILLEESS
|
||||||
|
|
||||||
|
:e [_f_i_l_e] Examine a new file.
|
||||||
|
^X^V Same as :e.
|
||||||
|
:n * Examine the (_N-th) next file from the command line.
|
||||||
|
:p * Examine the (_N-th) previous file from the command line.
|
||||||
|
:x * Examine the first (or _N-th) file from the command line.
|
||||||
|
^O^O Open the currently selected OSC8 hyperlink.
|
||||||
|
:d Delete the current file from the command line list.
|
||||||
|
= ^G :f Print current file name.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS
|
||||||
|
|
||||||
|
-_<_f_l_a_g_> Toggle a command line option [see OPTIONS below].
|
||||||
|
--_<_n_a_m_e_> Toggle a command line option, by name.
|
||||||
|
__<_f_l_a_g_> Display the setting of a command line option.
|
||||||
|
___<_n_a_m_e_> Display the setting of an option, by name.
|
||||||
|
+_c_m_d Execute the less cmd each time a new file is examined.
|
||||||
|
|
||||||
|
!_c_o_m_m_a_n_d Execute the shell command with $SHELL.
|
||||||
|
#_c_o_m_m_a_n_d Execute the shell command, expanded like a prompt.
|
||||||
|
|XX_c_o_m_m_a_n_d Pipe file between current pos & mark XX to shell command.
|
||||||
|
s _f_i_l_e Save input to a file.
|
||||||
|
v Edit the current file with $VISUAL or $EDITOR.
|
||||||
|
V Print version number of "less".
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
OOPPTTIIOONNSS
|
||||||
|
|
||||||
|
Most options may be changed either on the command line,
|
||||||
|
or from within less by using the - or -- command.
|
||||||
|
Options may be given in one of two forms: either a single
|
||||||
|
character preceded by a -, or a name preceded by --.
|
||||||
|
|
||||||
|
-? ........ --help
|
||||||
|
Display help (from command line).
|
||||||
|
-a ........ --search-skip-screen
|
||||||
|
Search skips current screen.
|
||||||
|
-A ........ --SEARCH-SKIP-SCREEN
|
||||||
|
Search starts just after target line.
|
||||||
|
-b [_N] .... --buffers=[_N]
|
||||||
|
Number of buffers.
|
||||||
|
-B ........ --auto-buffers
|
||||||
|
Don't automatically allocate buffers for pipes.
|
||||||
|
-c ........ --clear-screen
|
||||||
|
Repaint by clearing rather than scrolling.
|
||||||
|
-d ........ --dumb
|
||||||
|
Dumb terminal.
|
||||||
|
-D xx_c_o_l_o_r . --color=xx_c_o_l_o_r
|
||||||
|
Set screen colors.
|
||||||
|
-e -E .... --quit-at-eof --QUIT-AT-EOF
|
||||||
|
Quit at end of file.
|
||||||
|
-f ........ --force
|
||||||
|
Force open non-regular files.
|
||||||
|
-F ........ --quit-if-one-screen
|
||||||
|
Quit if entire file fits on first screen.
|
||||||
|
-g ........ --hilite-search
|
||||||
|
Highlight only last match for searches.
|
||||||
|
-G ........ --HILITE-SEARCH
|
||||||
|
Don't highlight any matches for searches.
|
||||||
|
-h [_N] .... --max-back-scroll=[_N]
|
||||||
|
Backward scroll limit.
|
||||||
|
-i ........ --ignore-case
|
||||||
|
Ignore case in searches that do not contain uppercase.
|
||||||
|
-I ........ --IGNORE-CASE
|
||||||
|
Ignore case in all searches.
|
||||||
|
-j [_N] .... --jump-target=[_N]
|
||||||
|
Screen position of target lines.
|
||||||
|
-J ........ --status-column
|
||||||
|
Display a status column at left edge of screen.
|
||||||
|
-k _f_i_l_e ... --lesskey-file=_f_i_l_e
|
||||||
|
Use a compiled lesskey file.
|
||||||
|
-K ........ --quit-on-intr
|
||||||
|
Exit less in response to ctrl-C.
|
||||||
|
-L ........ --no-lessopen
|
||||||
|
Ignore the LESSOPEN environment variable.
|
||||||
|
-m -M .... --long-prompt --LONG-PROMPT
|
||||||
|
Set prompt style.
|
||||||
|
-n ......... --line-numbers
|
||||||
|
Suppress line numbers in prompts and messages.
|
||||||
|
-N ......... --LINE-NUMBERS
|
||||||
|
Display line number at start of each line.
|
||||||
|
-o [_f_i_l_e] .. --log-file=[_f_i_l_e]
|
||||||
|
Copy to log file (standard input only).
|
||||||
|
-O [_f_i_l_e] .. --LOG-FILE=[_f_i_l_e]
|
||||||
|
Copy to log file (unconditionally overwrite).
|
||||||
|
-p _p_a_t_t_e_r_n . --pattern=[_p_a_t_t_e_r_n]
|
||||||
|
Start at pattern (from command line).
|
||||||
|
-P [_p_r_o_m_p_t] --prompt=[_p_r_o_m_p_t]
|
||||||
|
Define new prompt.
|
||||||
|
-q -Q .... --quiet --QUIET --silent --SILENT
|
||||||
|
Quiet the terminal bell.
|
||||||
|
-r -R .... --raw-control-chars --RAW-CONTROL-CHARS
|
||||||
|
Output "raw" control characters.
|
||||||
|
-s ........ --squeeze-blank-lines
|
||||||
|
Squeeze multiple blank lines.
|
||||||
|
-S ........ --chop-long-lines
|
||||||
|
Chop (truncate) long lines rather than wrapping.
|
||||||
|
-t _t_a_g .... --tag=[_t_a_g]
|
||||||
|
Find a tag.
|
||||||
|
-T [_t_a_g_s_f_i_l_e] --tag-file=[_t_a_g_s_f_i_l_e]
|
||||||
|
Use an alternate tags file.
|
||||||
|
-u -U .... --underline-special --UNDERLINE-SPECIAL
|
||||||
|
Change handling of backspaces, tabs and carriage returns.
|
||||||
|
-V ........ --version
|
||||||
|
Display the version number of "less".
|
||||||
|
-w ........ --hilite-unread
|
||||||
|
Highlight first new line after forward-screen.
|
||||||
|
-W ........ --HILITE-UNREAD
|
||||||
|
Highlight first new line after any forward movement.
|
||||||
|
-x [_N[,...]] --tabs=[_N[,...]]
|
||||||
|
Set tab stops.
|
||||||
|
-X ........ --no-init
|
||||||
|
Don't use termcap init/deinit strings.
|
||||||
|
-y [_N] .... --max-forw-scroll=[_N]
|
||||||
|
Forward scroll limit.
|
||||||
|
-z [_N] .... --window=[_N]
|
||||||
|
Set size of window.
|
||||||
|
-" [_c[_c]] . --quotes=[_c[_c]]
|
||||||
|
Set shell quote characters.
|
||||||
|
-~ ........ --tilde
|
||||||
|
Don't display tildes after end of file.
|
||||||
|
-# [_N] .... --shift=[_N]
|
||||||
|
Set horizontal scroll amount (0 = one half screen width).
|
||||||
|
|
||||||
|
--exit-follow-on-close
|
||||||
|
Exit F command on a pipe when writer closes pipe.
|
||||||
|
--file-size
|
||||||
|
Automatically determine the size of the input file.
|
||||||
|
--follow-name
|
||||||
|
The F command changes files if the input file is renamed.
|
||||||
|
--form-feed
|
||||||
|
Stop scrolling when a form feed character is reached.
|
||||||
|
--header=[_L[,_C[,_N]]]
|
||||||
|
Use _L lines (starting at line _N) and _C columns as headers.
|
||||||
|
--incsearch
|
||||||
|
Search file as each pattern character is typed in.
|
||||||
|
--intr=[_C]
|
||||||
|
Use _C instead of ^X to interrupt a read.
|
||||||
|
--lesskey-context=_t_e_x_t
|
||||||
|
Use lesskey source file contents.
|
||||||
|
--lesskey-src=_f_i_l_e
|
||||||
|
Use a lesskey source file.
|
||||||
|
--line-num-width=[_N]
|
||||||
|
Set the width of the -N line number field to _N characters.
|
||||||
|
--match-shift=[_N]
|
||||||
|
Show at least _N characters to the left of a search match.
|
||||||
|
--modelines=[_N]
|
||||||
|
Read _N lines from the input file and look for vim modelines.
|
||||||
|
--mouse
|
||||||
|
Enable mouse input.
|
||||||
|
--no-edit-warn
|
||||||
|
Don't warn when using v command on a file opened via LESSOPEN.
|
||||||
|
--no-keypad
|
||||||
|
Don't send termcap keypad init/deinit strings.
|
||||||
|
--no-histdups
|
||||||
|
Remove duplicates from command history.
|
||||||
|
--no-number-headers
|
||||||
|
Don't give line numbers to header lines.
|
||||||
|
--no-paste
|
||||||
|
Ignore pasted input.
|
||||||
|
--no-search-header-lines
|
||||||
|
Searches do not include header lines.
|
||||||
|
--no-search-header-columns
|
||||||
|
Searches do not include header columns.
|
||||||
|
--no-search-headers
|
||||||
|
Searches do not include header lines or columns.
|
||||||
|
--no-vbell
|
||||||
|
Disable the terminal's visual bell.
|
||||||
|
--redraw-on-quit
|
||||||
|
Redraw final screen when quitting.
|
||||||
|
--rscroll=[_C]
|
||||||
|
Set the character used to mark truncated lines.
|
||||||
|
--save-marks
|
||||||
|
Retain marks across invocations of less.
|
||||||
|
--search-options=[EFKNRW-]
|
||||||
|
Set default options for every search.
|
||||||
|
--show-preproc-errors
|
||||||
|
Display a message if preprocessor exits with an error status.
|
||||||
|
--proc-backspace
|
||||||
|
Process backspaces for bold/underline.
|
||||||
|
--PROC-BACKSPACE
|
||||||
|
Treat backspaces as control characters.
|
||||||
|
--proc-return
|
||||||
|
Delete carriage returns before newline.
|
||||||
|
--PROC-RETURN
|
||||||
|
Treat carriage returns as control characters.
|
||||||
|
--proc-tab
|
||||||
|
Expand tabs to spaces.
|
||||||
|
--PROC-TAB
|
||||||
|
Treat tabs as control characters.
|
||||||
|
--status-col-width=[_N]
|
||||||
|
Set the width of the -J status column to _N characters.
|
||||||
|
--status-line
|
||||||
|
Highlight or color the entire line containing a mark.
|
||||||
|
--use-backslash
|
||||||
|
Subsequent options use backslash as escape char.
|
||||||
|
--use-color
|
||||||
|
Enables colored text.
|
||||||
|
--wheel-lines=[_N]
|
||||||
|
Each click of the mouse wheel moves _N lines.
|
||||||
|
--wordwrap
|
||||||
|
Wrap lines at spaces.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
LLIINNEE EEDDIITTIINNGG
|
||||||
|
|
||||||
|
These keys can be used to edit text being entered
|
||||||
|
on the "command line" at the bottom of the screen.
|
||||||
|
|
||||||
|
RightArrow ..................... ESC-l ... Move cursor right one character.
|
||||||
|
LeftArrow ...................... ESC-h ... Move cursor left one character.
|
||||||
|
ctrl-RightArrow ESC-RightArrow ESC-w ... Move cursor right one word.
|
||||||
|
ctrl-LeftArrow ESC-LeftArrow ESC-b ... Move cursor left one word.
|
||||||
|
HOME ........................... ESC-0 ... Move cursor to start of line.
|
||||||
|
END ............................ ESC-$ ... Move cursor to end of line.
|
||||||
|
BACKSPACE ................................ Delete char to left of cursor.
|
||||||
|
DELETE ......................... ESC-x ... Delete char under cursor.
|
||||||
|
ctrl-BACKSPACE ESC-BACKSPACE ........... Delete word to left of cursor.
|
||||||
|
ctrl-DELETE .... ESC-DELETE .... ESC-X ... Delete word under cursor.
|
||||||
|
ctrl-U ......... ESC (MS-DOS only) ....... Delete entire line.
|
||||||
|
UpArrow ........................ ESC-k ... Retrieve previous command line.
|
||||||
|
DownArrow ...................... ESC-j ... Retrieve next command line.
|
||||||
|
TAB ...................................... Complete filename & cycle.
|
||||||
|
SHIFT-TAB ...................... ESC-TAB Complete filename & reverse cycle.
|
||||||
|
ctrl-L ................................... Complete filename, list all.
|
||||||
|
|||||||
@@ -42,3 +42,68 @@
|
|||||||
?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line.
|
?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line.
|
||||||
n * Repeat previous search (for _N-th occurrence).
|
n * Repeat previous search (for _N-th occurrence).
|
||||||
N * Repeat previous search in reverse direction.
|
N * Repeat previous search in reverse direction.
|
||||||
|
ESC-n * Repeat previous search, spanning files.
|
||||||
|
ESC-N * Repeat previous search, reverse dir. & spanning files.
|
||||||
|
^O^N ^On * Search forward for (_N-th) OSC8 hyperlink.
|
||||||
|
^O^P ^Op * Search backward for (_N-th) OSC8 hyperlink.
|
||||||
|
^O^L ^Ol Jump to the currently selected OSC8 hyperlink.
|
||||||
|
ESC-u Undo (toggle) search highlighting.
|
||||||
|
ESC-U Clear search highlighting.
|
||||||
|
&_p_a_t_t_e_r_n * Display only matching lines.
|
||||||
|
---------------------------------------------------
|
||||||
|
Search is case-sensitive unless changed with -i or -I.
|
||||||
|
A search pattern may begin with one or more of:
|
||||||
|
^N or ! Search for NON-matching lines.
|
||||||
|
^E or * Search multiple files (pass thru END OF FILE).
|
||||||
|
^F or @ Start search at FIRST file (for /) or last file (for ?).
|
||||||
|
^K Highlight matches, but don't move (KEEP position).
|
||||||
|
^R Don't use REGULAR EXPRESSIONS.
|
||||||
|
^S _n Search for match in _n-th parenthesized subpattern.
|
||||||
|
^W WRAP search if no match found.
|
||||||
|
^L Enter next character literally into pattern.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
JJUUMMPPIINNGG
|
||||||
|
|
||||||
|
g < ESC-< * Go to first line in file (or line _N).
|
||||||
|
G > ESC-> * Go to last line in file (or line _N).
|
||||||
|
p % * Go to beginning of file (or _N percent into file).
|
||||||
|
t * Go to the (_N-th) next tag.
|
||||||
|
T * Go to the (_N-th) previous tag.
|
||||||
|
{ ( [ * Find close bracket } ) ].
|
||||||
|
} ) ] * Find open bracket { ( [.
|
||||||
|
ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>.
|
||||||
|
ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>.
|
||||||
|
---------------------------------------------------
|
||||||
|
Each "find close bracket" command goes forward to the close bracket
|
||||||
|
matching the (_N-th) open bracket in the top line.
|
||||||
|
Each "find open bracket" command goes backward to the open bracket
|
||||||
|
matching the (_N-th) close bracket in the bottom line.
|
||||||
|
|
||||||
|
m_<_l_e_t_t_e_r_> Mark the current top line with <letter>.
|
||||||
|
M_<_l_e_t_t_e_r_> Mark the current bottom line with <letter>.
|
||||||
|
'_<_l_e_t_t_e_r_> Go to a previously marked position.
|
||||||
|
'' Go to the previous position.
|
||||||
|
^X^X Same as '.
|
||||||
|
ESC-m_<_l_e_t_t_e_r_> Clear a mark.
|
||||||
|
---------------------------------------------------
|
||||||
|
A mark is any upper-case or lower-case letter.
|
||||||
|
Certain marks are predefined:
|
||||||
|
^ means beginning of the file
|
||||||
|
$ means end of the file
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CCHHAANNGGIINNGG FFIILLEESS
|
||||||
|
|
||||||
|
:e [_f_i_l_e] Examine a new file.
|
||||||
|
^X^V Same as :e.
|
||||||
|
:n * Examine the (_N-th) next file from the command line.
|
||||||
|
:p * Examine the (_N-th) previous file from the command line.
|
||||||
|
:x * Examine the first (or _N-th) file from the command line.
|
||||||
|
^O^O Open the currently selected OSC8 hyperlink.
|
||||||
|
:d Delete the current file from the command line list.
|
||||||
|
= ^G :f Print current file name.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user