From 6ecd7520ccf6f810037980156dbc2c9aac905226 Mon Sep 17 00:00:00 2001 From: Yee Cheng Chin Date: Mon, 4 Nov 2024 05:52:24 -0500 Subject: [PATCH] Dark mode improve docs for v:os_appearance and add tests Make sure docs for v:os_appearance make it clear that it is reflecting MacVim's appearance, not the OS, which matters when not using "automatic" in dark mode appearance. Also add some unit tests to test this part of the functionality to add test coverage. Also see #1479 --- runtime/doc/eval.txt | 7 ++- src/MacVim/MacVimTests/MacVimTests.m | 77 ++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index d34f6574e9..6d3087026c 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2439,9 +2439,12 @@ v:operator The last operator given in Normal mode. This is a single Read-only. *v:os_appearance* *os-appearance-variable* -v:os_appearance The current OS appearance mode. Useful if you want to change +v:os_appearance The current OS appearance mode. Useful if you want to change options |background| or |colorscheme| according to the - appearance of the GUI frontend. See also |OSAppearanceChanged|. + appearance of the GUI frontend. See also + |OSAppearanceChanged|. If the "Dark mode selection" setting + is not set to "Automatic", then this value will reflect that + setting instead. value description ~ 0 Light Mode (always 0 on unsupported platforms) 1 Dark Mode diff --git a/src/MacVim/MacVimTests/MacVimTests.m b/src/MacVim/MacVimTests/MacVimTests.m index 04a29f6cd8..cdfd33c639 100644 --- a/src/MacVim/MacVimTests/MacVimTests.m +++ b/src/MacVim/MacVimTests/MacVimTests.m @@ -458,6 +458,83 @@ - (void) testGuifontSystemMonospace { [self waitForVimClose]; } +/// Test that dark mode settings work and the corresponding Vim bindings are functional. +/// +/// Note that `v:os_appearance` and OSAppearanceChanged respond to the view's appearance +/// rather than the OS setting. When using manual light/dark or "use background" settings, +/// they do not reflect the current OS dark mode setting. +- (void) testDarkMode { + NSUserDefaults *ud = NSUserDefaults.standardUserDefaults; + + MMAppController *app = MMAppController.sharedInstance; + + [app openNewWindow:NewWindowClean activate:YES]; + [self waitForVimOpenAndMessages]; + + MMVimView *vimView = [[[app keyVimController] windowController] vimView]; + + // We just use the system appearance to determine the initial state. Otherwise + // we have to change the system appearance to light mode first which we don't + // have permission to do. + const BOOL systemUsingDarkMode = [[ud stringForKey:@"AppleInterfaceStyle"] isEqualToString:@"Dark"]; + const NSAppearance *systemAppearance = systemUsingDarkMode ? + [NSAppearance appearanceNamed: NSAppearanceNameDarkAqua] : [NSAppearance appearanceNamed: NSAppearanceNameAqua]; + + // Default setting uses system appearance + XCTAssertEqualObjects(vimView.effectiveAppearance, systemAppearance); + XCTAssertEqualObjects([[app keyVimController] evaluateVimExpression:@"v:os_appearance"], systemUsingDarkMode ? @"1" : @"0"); + + // Cache original settings / set up setting overrides + NSDictionary *defaults = [ud volatileDomainForName:NSArgumentDomain]; + NSMutableDictionary *newDefaults = [defaults mutableCopy]; + + // Manual Light / Dark mode setting + newDefaults[MMAppearanceModeSelectionKey] = [NSNumber numberWithInt:MMAppearanceModeSelectionLight]; + [ud setVolatileDomain:newDefaults forName:NSArgumentDomain]; + [app refreshAllAppearances]; + XCTAssertEqualObjects(vimView.effectiveAppearance, [NSAppearance appearanceNamed: NSAppearanceNameAqua]); + XCTAssertEqualObjects([[app keyVimController] evaluateVimExpression:@"v:os_appearance"], @"0"); + + // Set up a listener for OSAppearanceChanged event to make sure it's called + // when the view appearance changes. + [self sendStringToVim:@":let g:os_appearance_changed_called=0\n" withMods:0]; + [self sendStringToVim:@":autocmd OSAppearanceChanged * let g:os_appearance_changed_called+=1\n" withMods:0]; + [self waitForEventHandlingAndVimProcess]; + + newDefaults[MMAppearanceModeSelectionKey] = [NSNumber numberWithInt:MMAppearanceModeSelectionDark]; + [ud setVolatileDomain:newDefaults forName:NSArgumentDomain]; + [app refreshAllAppearances]; + XCTAssertEqualObjects(vimView.effectiveAppearance, [NSAppearance appearanceNamed: NSAppearanceNameDarkAqua]); + XCTAssertEqualObjects([[app keyVimController] evaluateVimExpression:@"v:os_appearance"], @"1"); + XCTAssertEqualObjects([[app keyVimController] evaluateVimExpression:@"g:os_appearance_changed_called"], @"1"); + + // "Use background" setting + [self sendStringToVim:@":set background=dark\n" withMods:0]; + [self waitForEventHandlingAndVimProcess]; + + newDefaults[MMAppearanceModeSelectionKey] = [NSNumber numberWithInt:MMAppearanceModeSelectionBackgroundOption]; + [NSUserDefaults.standardUserDefaults setVolatileDomain:newDefaults forName:NSArgumentDomain]; + [app refreshAllAppearances]; + XCTAssertEqualObjects(vimView.effectiveAppearance, [NSAppearance appearanceNamed: NSAppearanceNameDarkAqua]); + XCTAssertEqualObjects([[app keyVimController] evaluateVimExpression:@"v:os_appearance"], @"1"); + XCTAssertEqualObjects([[app keyVimController] evaluateVimExpression:@"g:os_appearance_changed_called"], @"1"); // we stayed in dark mode, so OSAppearnceChanged didn't trigger + + [self sendStringToVim:@":set background=light\n" withMods:0]; + [self waitForEventHandlingAndVimProcess]; + XCTAssertEqualObjects(vimView.effectiveAppearance, [NSAppearance appearanceNamed: NSAppearanceNameAqua]); + XCTAssertEqualObjects([[app keyVimController] evaluateVimExpression:@"v:os_appearance"], @"0"); + XCTAssertEqualObjects([[app keyVimController] evaluateVimExpression:@"g:os_appearance_changed_called"], @"2"); + + // Restore original settings and make sure it's reset + [NSUserDefaults.standardUserDefaults setVolatileDomain:defaults forName:NSArgumentDomain]; + [app refreshAllAppearances]; + XCTAssertEqualObjects(vimView.effectiveAppearance, systemAppearance); + + // Clean up + [[app keyVimController] sendMessage:VimShouldCloseMsgID data:nil]; + [self waitForVimClose]; +} + /// Test that document icon is shown in title bar when enabled. - (void) testTitlebarDocumentIcon { MMAppController *app = MMAppController.sharedInstance;