Add a command to list fonts

This commit is contained in:
Kovid Goyal 2017-11-10 11:02:32 +05:30
parent 1d7b650fd0
commit 43bf056f09
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 74 additions and 15 deletions

View File

@ -6,6 +6,9 @@ kitty is a feature full, cross-platform, *fast*, GPU based terminal emulator.
version 0.5.0 [future] version 0.5.0 [future]
--------------------------- ---------------------------
- Make it easy to select fonts by allowing listing of monospace fonts using:
kitty list-fonts
- macOS: Enable subpixel rendering of text for improved appearance - macOS: Enable subpixel rendering of text for improved appearance
- Linux: Support rendering of non-normalizable unicode combining characters by using harfbuzz - Linux: Support rendering of non-normalizable unicode combining characters by using harfbuzz

View File

@ -7,6 +7,9 @@ import sys
if len(sys.argv) > 1 and sys.argv[1] == 'icat': if len(sys.argv) > 1 and sys.argv[1] == 'icat':
from kitty.icat import main from kitty.icat import main
main(sys.argv[1:]) main(sys.argv[1:])
elif len(sys.argv) > 1 and sys.argv[1] == 'list-fonts':
from kitty.fonts.list import main
main(sys.argv[1:])
else: else:
from kitty.main import main from kitty.main import main
main() main()

View File

@ -34,6 +34,15 @@ def all_fonts_map():
return ans return ans
def list_fonts():
for fd in coretext_all_fonts():
f = fd['family']
if f:
fn = (f + ' ' + (fd['style'] or '')).strip()
is_mono = bool(fd['monospace'])
yield {'family': f, 'full_name': fn, 'is_monospace': is_mono}
def find_best_match(family, bold, italic): def find_best_match(family, bold, italic):
q = re.sub(r'\s+', ' ', family.lower()) q = re.sub(r'\s+', ' ', family.lower())
font_map = all_fonts_map() font_map = all_fonts_map()

View File

@ -19,6 +19,8 @@ attr_map = {(False, False): 'font_family',
def create_font_map(all_fonts): def create_font_map(all_fonts):
ans = {'family_map': {}, 'ps_map': {}, 'full_map': {}} ans = {'family_map': {}, 'ps_map': {}, 'full_map': {}}
for x in all_fonts: for x in all_fonts:
if 'path' not in x:
continue
f = (x.get('family') or '').lower() f = (x.get('family') or '').lower()
full = (x.get('full_name') or '').lower() full = (x.get('full_name') or '').lower()
ps = (x.get('postscript_name') or '').lower() ps = (x.get('postscript_name') or '').lower()
@ -33,14 +35,23 @@ def all_fonts_map(monospaced=True):
return create_font_map(fc_list(monospaced)) return create_font_map(fc_list(monospaced))
def list_fonts():
for fd in fc_list(False):
f = fd.get('family')
if f:
fn = fd.get('full_name') or (f + ' ' + fd.get('style', '')).strip()
is_mono = fd.get('spacing') == 'MONO'
yield {'family': f, 'full_name': fn, 'is_monospace': is_mono}
def find_best_match(family, bold=False, italic=False, monospaced=True): def find_best_match(family, bold=False, italic=False, monospaced=True):
q = re.sub(r'\s+', ' ', family.lower()) q = re.sub(r'\s+', ' ', family.lower())
font_map = all_fonts_map(monospaced) font_map = all_fonts_map(monospaced)
def score(candidate): def score(candidate):
bold_score = abs((FC_WEIGHT_BOLD if bold else FC_WEIGHT_REGULAR) - candidate['weight']) bold_score = abs((FC_WEIGHT_BOLD if bold else FC_WEIGHT_REGULAR) - candidate.get('weight', 0))
italic_score = abs((FC_SLANT_ITALIC if italic else FC_SLANT_ROMAN) - candidate['slant']) italic_score = abs((FC_SLANT_ITALIC if italic else FC_SLANT_ROMAN) - candidate.get('slant', 0))
monospace_match = 0 if candidate['spacing'] == 'MONO' else 1 monospace_match = 0 if candidate.get('spacing') == 'MONO' else 1
return bold_score + italic_score, monospace_match return bold_score + italic_score, monospace_match
# First look for an exact match # First look for an exact match
@ -56,8 +67,8 @@ def find_best_match(family, bold=False, italic=False, monospaced=True):
def face_from_font(font, pt_sz=11.0, xdpi=96.0, ydpi=96.0): def face_from_font(font, pt_sz=11.0, xdpi=96.0, ydpi=96.0):
font = fc_font(pt_sz, (xdpi + ydpi) / 2.0, font['path'], font['index']) font = fc_font(pt_sz, (xdpi + ydpi) / 2.0, font['path'], font.get('index', 0))
return Face(font['path'], font['index'], font['hinting'], font['hint_style'], pt_sz, xdpi, ydpi) return Face(font['path'], font.get('index', 0), font.get('hinting', False), font.get('hint_style', 0), pt_sz, xdpi, ydpi)
def resolve_family(f, main_family, bold, italic): def resolve_family(f, main_family, bold, italic):
@ -86,8 +97,8 @@ def get_font_files(opts):
def font_for_family(family): def font_for_family(family):
ans = find_best_match(family) ans = find_best_match(family, monospaced=False)
return ans, ans['weight'] >= FC_WEIGHT_BOLD, ans['slant'] != FC_SLANT_ROMAN return ans, ans.get('weight', 0) >= FC_WEIGHT_BOLD, ans.get('slant', FC_SLANT_ROMAN) != FC_SLANT_ROMAN
def font_for_text(text, current_font_family='monospace', pt_sz=11.0, xdpi=96.0, ydpi=96.0, bold=False, italic=False): def font_for_text(text, current_font_family='monospace', pt_sz=11.0, xdpi=96.0, ydpi=96.0, bold=False, italic=False):

35
kitty/fonts/list.py Normal file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import sys
from kitty.constants import isosx
if isosx:
from .core_text import list_fonts
else:
from .fontconfig import list_fonts
def create_family_groups(monospaced=True):
g = {}
for f in list_fonts():
if not monospaced or f['is_monospace']:
g.setdefault(f['family'], []).append(f)
return g
def main(argv):
isatty = sys.stdout.isatty()
groups = create_family_groups()
for k in sorted(groups, key=lambda x: x.lower()):
if isatty:
print('\033[1;32m' + k + '\033[m')
else:
print(k)
for f in sorted(groups[k], key=lambda x: x['full_name'].lower()):
p = f['full_name']
if isatty:
p = '\033[3m' + p + '\033[m'
print(' ', p)
print()

View File

@ -5,14 +5,12 @@
# by the OSes font system. Setting them manually is useful for font families # by the OSes font system. Setting them manually is useful for font families
# that have many weight variants like Book, Medium, Thick, etc. For example: # that have many weight variants like Book, Medium, Thick, etc. For example:
# font_family Operator Mono Book # font_family Operator Mono Book
# bold_font Operator Mono Thick # bold_font Operator Mono Medium
# bold_italic_font Operator Mono Medium # italic_font Operator Mono Book Italic
# or # bold_italic_font Operator Mono Medium Italic
# font_family SF Mono Medium #
# bold_font SF Mono Semibold # You can get a list of full family names available on your computer by running
# bold_italic_font SF Mono Semibold # kitty list-fonts
# Note that you should use the full family name but do not add Bold or Italic qualifiers
# to the name.
font_family monospace font_family monospace
italic_font auto italic_font auto
bold_font auto bold_font auto