Merge pull request #1463 from ychin/guifont-system-monospace

Support native macOS monospace font (SF Mono)
This commit is contained in:
Yee Cheng Chin
2023-12-08 02:09:39 -08:00
committed by GitHub
12 changed files with 188 additions and 12 deletions
+15 -4
View File
@@ -1129,11 +1129,22 @@ That's all. XLFDs are not used. For Chinese this is reported to work well: >
<
(Replace gui_gtk2 with gui_gtk3 for the GTK+ 3 GUI)
For Mac OSX you can use something like this: >
:set guifont=Monaco:h10
Also see 'macatsui', it can help fix display problems {not in MacVim}.
In MacVim, fonts with spaces are set like this: >
MacVim *macvim-guifont*
For MacVim you can use something like this: >
:set guifont=Menlo:h10
Fonts with spaces are set like this: >
:set guifont=DejaVu\ Sans\ Mono:h13
To use bold/italic fonts, use the fully specified PostScript name of the
font, like so: >
:set guifont=Menlo-Bold:h13
To use the system native monospace font (which is SF Mono in new macOS
versions), use the `-monospace-` keyword: >
:set guifont=-monospace-:h12
You can also specify the font weight of the native monospace font (refer to
Apple documentation for `NSFontWeight` for possible values): >
:set guifont=-monospace-Light:h11
:set guifont=-monospace-Medium:h11
<
Mono-spaced fonts *E236*
+3
View File
@@ -118,6 +118,9 @@ These are the non-standard options that MacVim supports:
'fuoptions' 'macligatures' 'macmeta' 'macthinstrokes'
'toolbariconsize' 'transparency'
These are GUI-related Vim options that have MacVim-specific behaviors:
'guifont'
*macvim-commands*
These are the non-standard commands that MacVim supports:
|:macaction| |:macmenu|
+1
View File
@@ -8622,6 +8622,7 @@ macvim-encoding gui_mac.txt /*macvim-encoding*
macvim-find gui_mac.txt /*macvim-find*
macvim-full-screen gui_mac.txt /*macvim-full-screen*
macvim-gestures gui_mac.txt /*macvim-gestures*
macvim-guifont gui.txt /*macvim-guifont*
macvim-help-menu gui_mac.txt /*macvim-help-menu*
macvim-hints gui_mac.txt /*macvim-hints*
macvim-internal-variables gui_mac.txt /*macvim-internal-variables*
+1
View File
@@ -87,6 +87,7 @@ NS_ASSUME_NONNULL_BEGIN
// NSFontChanging methods
//
- (void)changeFont:(nullable id)sender;
- (NSFontPanelModeMask)validModesForFontPanel:(NSFontPanel *)fontPanel;
//
// NSMenuItemValidation
+18 -3
View File
@@ -1299,9 +1299,10 @@ static void grid_free(Grid *grid) {
MMMinRows * cellSize.height + insetSize.height + bot);
}
// Called when font panel selection has been made. Send the selected font to
// MMBackend so it would set guifont which will send a message back to MacVim to
// call MMWindowController::setFont.
// Called when font panel selection has been made or when adjusting font size
// using modifyFont/NSSizeUpFontAction. Send the selected font to MMBackend so
// it would set guifont which will send a message back to MacVim to call
// MMWindowController::setFont.
- (void)changeFont:(id)sender
{
NSFont *newFont = [sender convertFont:font];
@@ -1319,11 +1320,25 @@ static void grid_free(Grid *grid) {
[data appendBytes:&len length:sizeof(unsigned)];
[data appendBytes:[name UTF8String] length:len];
// We don't update guifontwide for now, as panel font selection
// shouldn't affect them. This does mean Cmd +/- does not work for
// them for now.
const unsigned wideLen = 0;
[data appendBytes:&wideLen length:sizeof(unsigned)];
[[self vimController] sendMessage:SetFontMsgID data:data];
}
}
}
- (NSFontPanelModeMask)validModesForFontPanel:(NSFontPanel *)fontPanel
{
// Lets the user pick only the font face / size, as other properties as not
// useful. Still enable text/document colors as these affect the preview.
// Otherwise it could just be white text on white background in the preview.
return NSFontPanelModesMaskStandardModes & (~NSFontPanelModeMaskAllEffects | NSFontPanelModeMaskTextColorEffect | NSFontPanelModeMaskDocumentColorEffect);
}
/// Specifies whether the menu item should be enabled/disabled.
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
+38 -1
View File
@@ -900,7 +900,44 @@ static BOOL isUnsafeMessage(int msgid);
NSString *name = [[NSString alloc]
initWithBytes:(void*)bytes length:len
encoding:NSUTF8StringEncoding];
NSFont *font = [NSFont fontWithName:name size:size];
NSFont *font = nil;
if ([name hasPrefix:MMSystemFontAlias]) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15
if (@available(macos 10.15, *)) {
NSFontWeight fontWeight = NSFontWeightRegular;
if (name.length > MMSystemFontAlias.length) {
const NSRange cmpRange = NSMakeRange(MMSystemFontAlias.length, name.length - MMSystemFontAlias.length);
if ([name compare:@"UltraLight" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightUltraLight;
else if ([name compare:@"Thin" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightThin;
else if ([name compare:@"Light" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightLight;
else if ([name compare:@"Regular" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightRegular;
else if ([name compare:@"Medium" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightMedium;
else if ([name compare:@"Semibold" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightSemibold;
else if ([name compare:@"Bold" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightBold;
else if ([name compare:@"Heavy" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightHeavy;
else if ([name compare:@"Black" options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame)
fontWeight = NSFontWeightBlack;
}
font = [NSFont monospacedSystemFontOfSize:size weight:fontWeight];
}
else
#endif
{
// Fallback to Menlo on older macOS versions that don't support the system monospace font API
font = [NSFont fontWithName:@"Menlo-Regular" size:size];
}
}
else {
font = [NSFont fontWithName:name size:size];
}
if (!font) {
// This should only happen if the system default font has changed
// name since MacVim was compiled in which case we fall back on
+2 -1
View File
@@ -433,7 +433,8 @@ enum {
extern NSString *VimFindPboardType;
// Alias for system monospace font name
extern NSString *MMSystemFontAlias;
@interface NSString (MMExtras)
+2
View File
@@ -40,6 +40,8 @@ NSString *MMRendererKey = @"MMRenderer";
// Vim find pasteboard type (string contains Vim regex patterns)
NSString *VimFindPboardType = @"VimFindPboardType";
NSString *MMSystemFontAlias = @"-monospace-";
int ASLogLevel = MM_ASL_LEVEL_DEFAULT;
+33
View File
@@ -10,6 +10,8 @@
#import <objc/runtime.h>
#import <Cocoa/Cocoa.h>
#import "Miscellaneous.h"
#import "MMAppController.h"
#import "MMApplication.h"
@@ -425,4 +427,35 @@ do { \
[self waitForVimClose];
}
/// Test that using "-monospace-" for system default monospace font works.
- (void) testGuifontSystemMonospace {
MMAppController *app = MMAppController.sharedInstance;
[app openNewWindow:NewWindowClean activate:YES];
[self waitForVimOpenAndMessages];
MMTextView *textView = [[[[app keyVimController] windowController] vimView] textView];
XCTAssertEqualObjects(@"Menlo-Regular", [[textView font] fontName]);
[self sendStringToVim:@":set guifont=-monospace-\n" withMods:0];
[self waitForEventHandlingAndVimProcess];
XCTAssertEqualObjects([textView font], [NSFont monospacedSystemFontOfSize:11 weight:NSFontWeightRegular]);
[self sendStringToVim:@":set guifont=-monospace-Heavy:h12\n" withMods:0];
[self waitForEventHandlingAndVimProcess];
XCTAssertEqualObjects([textView font], [NSFont monospacedSystemFontOfSize:12 weight:NSFontWeightHeavy]);
[[[app keyVimController] windowController] fontSizeUp:nil];
[self waitForEventHandlingAndVimProcess];
XCTAssertEqualObjects([textView font], [NSFont monospacedSystemFontOfSize:13 weight:NSFontWeightHeavy]);
[[[app keyVimController] windowController] fontSizeDown:nil];
[self waitForEventHandlingAndVimProcess];
XCTAssertEqualObjects([textView font], [NSFont monospacedSystemFontOfSize:12 weight:NSFontWeightHeavy]);
// Clean up
[[app keyVimController] sendMessage:VimShouldCloseMsgID data:nil];
[self waitForVimClose];
}
@end
+2 -1
View File
@@ -153,7 +153,8 @@ enum {
@interface NSNumber (MMExtras)
// HACK to allow font size to be changed via menu (bound to Cmd+/Cmd-)
// Used by modifyFont:/convertFont: to allow font size to be changed via menu
// (bound to Cmd+/Cmd-) or using macaction fontSizeUp:/fontSizeDown:.
- (NSInteger)tag;
@end
+44 -2
View File
@@ -32,11 +32,13 @@ static BOOL MMNoMRU = NO;
static NSString *MMDefaultFontName = @"Menlo-Regular";
static int MMDefaultFontSize = 11;
static char *MMDefaultFontStr = "Menlo-Regular:h11";
static char *MMDefaultFontSizeStr = "h11";
static int MMMinFontSize = 6;
static int MMMaxFontSize = 100;
// This is duplicated in MMVimController. Could consolidate in the future.
static NSString *(system_font_weights[]) = { @"UltraLight", @"Thin", @"Light", @"Regular", @"Medium", @"Semibold", @"Bold", @"Heavy", @"Black" };
static BOOL MMShareFindPboard = YES;
static GuiFont gui_macvim_font_with_name(char_u *name);
@@ -1141,6 +1143,22 @@ gui_macvim_font_with_name(char_u *name)
componentsJoinedByString:@" "];
}
const BOOL isSystemFont = [fontName hasPrefix:MMSystemFontAlias];
if (isSystemFont) {
if (fontName.length > MMSystemFontAlias.length) {
BOOL invalidWeight = YES;
const NSRange cmpRange = NSMakeRange(MMSystemFontAlias.length, fontName.length - MMSystemFontAlias.length);
for (size_t i = 0; i < ARRAY_LENGTH(system_font_weights); i++) {
if ([fontName compare:system_font_weights[i] options:NSCaseInsensitiveSearch range:cmpRange] == NSOrderedSame) {
invalidWeight = NO;
break;
}
}
if (invalidWeight)
return NOFONT;
}
}
if (!parseFailed && [fontName length] > 0) {
if (size < MMMinFontSize) size = MMMinFontSize;
if (size > MMMaxFontSize) size = MMMaxFontSize;
@@ -1148,6 +1166,7 @@ gui_macvim_font_with_name(char_u *name)
// If the default font is requested we don't need to check if NSFont
// can load it. Otherwise we ask NSFont if it can load it.
if ([fontName isEqualToString:MMDefaultFontName]
|| isSystemFont
|| [NSFont fontWithName:fontName size:size])
return [[NSString alloc] initWithFormat:@"%@:h%d", fontName, size];
}
@@ -1170,7 +1189,9 @@ gui_mch_expand_font(optexpand_T *args, void *param, int (*add_match)(char_u *val
{
// If guifont is empty, and we want to fill in the orig value, suggest
// the default so the user can modify it.
if (add_match((char_u *)MMDefaultFontStr) != OK)
NSString *defaultFontStr = [NSString stringWithFormat:@"%@:h%d",
MMDefaultFontName, MMDefaultFontSize];
if (add_match((char_u *)[defaultFontStr UTF8String]) != OK)
return;
}
@@ -1185,6 +1206,27 @@ gui_mch_expand_font(optexpand_T *args, void *param, int (*add_match)(char_u *val
return;
}
if (!wide) {
// Add system-native monospace font alias to completion.
char buf[40];
[MMSystemFontAlias getCString:buf maxLength:ARRAY_LENGTH(buf) encoding:NSASCIIStringEncoding];
if (add_match((char_u*)buf) != OK)
return;
const size_t fontAliasLen = STRLEN(buf);
if (STRNCMP(xp->xp_pattern, buf, fontAliasLen) == 0) {
// We additionally complete with font weights like "bold". We only
// do so if starting with "-monospace-" already to avoid spamming
// the user with too many variations on this.
for (size_t i = 0; i < ARRAY_LENGTH(system_font_weights); i++) {
[system_font_weights[i] getCString:buf+fontAliasLen
maxLength:ARRAY_LENGTH(buf)-fontAliasLen
encoding:NSASCIIStringEncoding];
if (add_match((char_u*)buf) != OK)
return;
}
}
}
NSFontManager *fontManager = [NSFontManager sharedFontManager];
NSArray<NSString *> *availableFonts;
if (wide)
+29
View File
@@ -433,6 +433,28 @@ func Test_set_guifont()
let &guifont = guifont_saved
endfunc
func Test_set_guifont_macvim()
CheckFeature gui_macvim
let guifont_saved = &guifont
let guifontwide_saved = &guifontwide
set guifont=-monospace-
call assert_equal('-monospace-:h11', getfontname())
set guifont=-monospace-Semibold
call assert_equal('-monospace-Semibold:h11', getfontname())
call assert_fails('set guifont=-monospace-SemiboldInvalidWeight', 'E596')
set guifont=Menlo\ Regular
call assert_equal('Menlo Regular:h11', getfontname())
set guifont=
call assert_equal('Menlo-Regular:h11', getfontname())
let &guifontwide = guifontwide_saved
let &guifont = guifont_saved
endfunc
func Test_set_guifontset()
CheckFeature xfontset
let skipped = ''
@@ -641,6 +663,13 @@ func Test_expand_guifont()
call assert_equal(['Menlo-Regular'], getcompletion('set guifont=Menl*lar$', 'cmdline'))
call assert_equal(['Menlo-Regular'], getcompletion('set guifontwide=Menl*lar$', 'cmdline'))
" Test system monospace font option. It's always the first option after
" the existing font.
call assert_equal('-monospace-', getcompletion('set guifont=', 'cmdline')[1])
call assert_equal('-monospace-', getcompletion('set guifont=-monospace-', 'cmdline')[0])
call assert_equal('-monospace-UltraLight', getcompletion('set guifont=-monospace-', 'cmdline')[1])
call assert_equal(['-monospace-Medium'], getcompletion('set guifont=-monospace-Med', 'cmdline'))
" Make sure non-monospace fonts are filtered out only in 'guifont'
call assert_equal([], getcompletion('set guifont=Hel*tica$', 'cmdline'))
call assert_equal(['Helvetica'], getcompletion('set guifontwide=Hel*tica$', 'cmdline'))