diff --git a/freetype/__init__.py b/freetype/__init__.py index d97a5f4a9..aa29bf20d 100644 --- a/freetype/__init__.py +++ b/freetype/__init__.py @@ -42,7 +42,7 @@ class _FT_Library_Wrapper(FT_Library): # This does not work properly (seg fault on sime system (OSX)) # self._ft_done_freetype(self) pass - + def _init_freetype(): global _handle @@ -991,6 +991,8 @@ class Face( object ): if self._FT_Face is not None: FT_Done_Face( self._FT_Face ) + def __repr__(self): + return 'Face({})'.format(self.family_name) def attach_file( self, filename ): ''' diff --git a/kitty/config.py b/kitty/config.py index 02cd2c5c2..5c61d346d 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -6,8 +6,6 @@ import re from collections import namedtuple from typing import Tuple -from .fonts import validate_monospace_font - key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$') # Color definitions {{{ @@ -206,7 +204,6 @@ type_map = { 'cursor_opacity': float, 'cursor_shape': to_cursor_shape, 'cursor_blink': to_bool, - 'font_family': validate_monospace_font, } for name in 'foreground foreground_bold background cursor'.split(): diff --git a/kitty/fonts.py b/kitty/fonts.py index 9bdaef76d..dc9a81baa 100644 --- a/kitty/fonts.py +++ b/kitty/fonts.py @@ -4,6 +4,8 @@ import subprocess import re +from collections import namedtuple +from functools import lru_cache from freetype import Face @@ -11,43 +13,41 @@ from freetype import Face def escape_family_name(name): return re.sub(r'([-:,\\])', lambda m: '\\' + m.group(1), name) +Font = namedtuple('Font', 'face hinting hintstyle bold italic') -def fc_match(q, bold=False, italic=False): + +@lru_cache() +def get_font_information(q, bold=False, italic=False): q = escape_family_name(q) if bold: q += ':bold=200' if italic: q += ':slant=100' - return subprocess.check_output(['fc-match', q, '-f', '%{file}']).decode('utf-8') - - -def validate_monospace_font(raw_name): - raw = fc_match(raw_name) - if not raw: - raise ValueError('Failed to find a font matching the name: {}'.format(raw_name)) - f = Face(raw) - if not f.is_fixed_width: - raise ValueError('The font {} is not a monospace font'.format(raw_name)) - return f, raw_name + raw = subprocess.check_output(['fc-match', q, '-f', '%{file}\x31%{hinting}\x31%{hintstyle}']).decode('utf-8') + parts = raw.split('\x31') + hintstyle, hinting = 1, 'True' + if len(parts) == 3: + path, hinting, hintstyle = parts + else: + path = parts[0] + hinting = hinting.lower() == 'true' + hintstyle = int(hintstyle) + return Font(path, hinting, hintstyle, bold, italic) def get_font_files(family): ans = {} + n = get_font_information(family) + ans['regular'] = Font(Face(n.face), n.hinting, n.hintstyle, n.bold, n.italic) - b = fc_match(family, bold=True) - if b: - ans['bold'] = Face(b) - i = fc_match(family, italic=True) - if i: - ans['italic'] = Face(i) - bi = fc_match(family, True, True) - if bi: - ans['bi'] = Face(bi) + def do(key): + b = get_font_information(family, bold=key in ('bold', 'bi'), italic=key in ('italic', 'bi')) + if b.face != n.face: + ans[key] = Font(Face(b.face), b.hinting, b.hintstyle, b.bold, b.italic) + do('bold'), do('italic'), do('bi') return ans +@lru_cache() def load_font_family(r): - face, raw_name = r - ans = get_font_files(raw_name) - ans['regular'] = face - return ans + return get_font_files(r)