Linux: Allow using fonts with spacing=90 in addition to fonts with spacing=100
Fixes #1968
This commit is contained in:
parent
41b0f8852f
commit
bc302dad23
4 changed files with 40 additions and 28 deletions
|
|
@ -22,6 +22,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
|||
- Fix incorrect rendering of some symbols when followed by a space while using
|
||||
the PowerLine font which does not have a space glyph (:iss:`1225`)
|
||||
|
||||
- Linux: Allow using fonts with spacing=90 in addition to fonts with
|
||||
spacing=100 (:iss:`1968`)
|
||||
|
||||
|
||||
0.14.4 [2019-08-31]
|
||||
---------------------
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ only monospace fonts, since every cell in the grid has to be the same size. If
|
|||
your font is not listed in ``kitty list-fonts`` it means that it is not
|
||||
monospace. On Linux you can list all monospace fonts with::
|
||||
|
||||
fc-list : family spacing | grep spacing=100
|
||||
fc-list : family spacing | grep -e spacing=100 -e spacing=90
|
||||
|
||||
Note that the spacing property is calculated by fontconfig based on actual
|
||||
glyph widths in the font. If for some reason fontconfig concludes your favorite
|
||||
|
|
|
|||
|
|
@ -83,19 +83,19 @@ font_set(FcFontSet *fs) {
|
|||
|
||||
static PyObject*
|
||||
fc_list(PyObject UNUSED *self, PyObject *args) {
|
||||
int allow_bitmapped_fonts = 0, only_monospaced_fonts = 1;
|
||||
int allow_bitmapped_fonts = 0, spacing = -1;
|
||||
PyObject *ans = NULL;
|
||||
FcObjectSet *os = NULL;
|
||||
FcPattern *pat = NULL;
|
||||
FcFontSet *fs = NULL;
|
||||
if (!PyArg_ParseTuple(args, "|pp", &only_monospaced_fonts, &allow_bitmapped_fonts)) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "|ip", &spacing, &allow_bitmapped_fonts)) return NULL;
|
||||
pat = FcPatternCreate();
|
||||
if (pat == NULL) return PyErr_NoMemory();
|
||||
if (!allow_bitmapped_fonts) {
|
||||
AP(FcPatternAddBool, FC_OUTLINE, true, "outline");
|
||||
AP(FcPatternAddBool, FC_SCALABLE, true, "scalable");
|
||||
}
|
||||
if (only_monospaced_fonts) AP(FcPatternAddInteger, FC_SPACING, FC_MONO, "spacing");
|
||||
if (spacing > -1) AP(FcPatternAddInteger, FC_SPACING, spacing, "spacing");
|
||||
os = FcObjectSetBuild(FC_FILE, FC_POSTSCRIPT_NAME, FC_FAMILY, FC_STYLE, FC_FULLNAME, FC_WEIGHT, FC_WIDTH, FC_SLANT, FC_HINT_STYLE, FC_INDEX, FC_HINTING, FC_SCALABLE, FC_OUTLINE, FC_COLOR, FC_SPACING, NULL);
|
||||
if (!os) { PyErr_SetString(PyExc_ValueError, "Failed to create fontconfig object set"); goto end; }
|
||||
fs = FcFontList(NULL, pat, os);
|
||||
|
|
@ -147,21 +147,21 @@ end:
|
|||
static PyObject*
|
||||
fc_match(PyObject UNUSED *self, PyObject *args) {
|
||||
char *family = NULL;
|
||||
int bold = 0, italic = 0, allow_bitmapped_fonts = 0, monospaced = 0;
|
||||
int bold = 0, italic = 0, allow_bitmapped_fonts = 0, spacing = FC_MONO;
|
||||
double size_in_pts = 0, dpi = 0;
|
||||
FcPattern *pat = NULL;
|
||||
PyObject *ans = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|zppppdd", &family, &bold, &italic, &monospaced, &allow_bitmapped_fonts, &size_in_pts, &dpi)) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "|zppppdd", &family, &bold, &italic, &spacing, &allow_bitmapped_fonts, &size_in_pts, &dpi)) return NULL;
|
||||
pat = FcPatternCreate();
|
||||
if (pat == NULL) return PyErr_NoMemory();
|
||||
|
||||
if (family && strlen(family) > 0) AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)family, "family");
|
||||
if (monospaced) {
|
||||
if (spacing >= FC_DUAL) {
|
||||
// pass the family,monospace as the family parameter to fc-match,
|
||||
// which will fallback to using monospace if the family does not match.
|
||||
AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)"monospace", "family");
|
||||
AP(FcPatternAddInteger, FC_SPACING, FC_MONO, "spacing");
|
||||
AP(FcPatternAddInteger, FC_SPACING, spacing, "spacing");
|
||||
}
|
||||
if (!allow_bitmapped_fonts) {
|
||||
AP(FcPatternAddBool, FC_OUTLINE, true, "outline");
|
||||
|
|
@ -243,5 +243,9 @@ init_fontconfig_library(PyObject *module) {
|
|||
PyModule_AddIntMacro(module, FC_WEIGHT_BOLD);
|
||||
PyModule_AddIntMacro(module, FC_SLANT_ITALIC);
|
||||
PyModule_AddIntMacro(module, FC_SLANT_ROMAN);
|
||||
PyModule_AddIntMacro(module, FC_PROPORTIONAL);
|
||||
PyModule_AddIntMacro(module, FC_DUAL);
|
||||
PyModule_AddIntMacro(module, FC_MONO);
|
||||
PyModule_AddIntMacro(module, FC_CHARCELL);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
from kitty.fast_data_types import (
|
||||
FC_SLANT_ITALIC, FC_SLANT_ROMAN, FC_WEIGHT_BOLD, FC_WEIGHT_REGULAR,
|
||||
fc_list, fc_match as fc_match_impl,
|
||||
fc_list, fc_match as fc_match_impl, FC_DUAL, FC_MONO
|
||||
)
|
||||
|
||||
attr_map = {(False, False): 'font_family',
|
||||
|
|
@ -32,15 +32,19 @@ def create_font_map(all_fonts):
|
|||
|
||||
@lru_cache()
|
||||
def all_fonts_map(monospaced=True):
|
||||
return create_font_map(fc_list(monospaced))
|
||||
if monospaced:
|
||||
ans = fc_list(FC_DUAL) + fc_list(FC_MONO)
|
||||
else:
|
||||
ans = fc_list()
|
||||
return create_font_map(ans)
|
||||
|
||||
|
||||
def list_fonts():
|
||||
for fd in fc_list(False):
|
||||
for fd in fc_list():
|
||||
f = fd.get('family')
|
||||
if f:
|
||||
fn = fd.get('full_name') or (f + ' ' + fd.get('style', '')).strip()
|
||||
is_mono = fd.get('spacing') == 'MONO'
|
||||
is_mono = fd.get('spacing') in ('MONO', 'DUAL')
|
||||
yield {'family': f, 'full_name': fn, 'is_monospace': is_mono}
|
||||
|
||||
|
||||
|
|
@ -49,8 +53,8 @@ def family_name_to_key(family):
|
|||
|
||||
|
||||
@lru_cache()
|
||||
def fc_match(family, bold, italic):
|
||||
return fc_match_impl(family, bold, italic)
|
||||
def fc_match(family, bold, italic, spacing=FC_MONO):
|
||||
return fc_match_impl(family, bold, italic, spacing)
|
||||
|
||||
|
||||
def find_best_match(family, bold=False, italic=False, monospaced=True):
|
||||
|
|
@ -71,20 +75,21 @@ def score(candidate):
|
|||
return candidates[0]
|
||||
|
||||
# Use fc-match to see if we can find a monospaced font that matches family
|
||||
possibility = fc_match(family, False, False)
|
||||
for key, map_key in (('postscript_name', 'ps_map'), ('full_name', 'full_map'), ('family', 'family_map')):
|
||||
val = possibility.get(key)
|
||||
if val:
|
||||
candidates = font_map[map_key].get(family_name_to_key(val))
|
||||
if candidates:
|
||||
if len(candidates) == 1:
|
||||
# happens if the family name is an alias, so we search with
|
||||
# the actual family name to see if we can find all the
|
||||
# fonts in the family.
|
||||
family_name_candidates = font_map['family_map'].get(family_name_to_key(candidates[0]['family']))
|
||||
if family_name_candidates and len(family_name_candidates) > 1:
|
||||
candidates = family_name_candidates
|
||||
return sorted(candidates, key=score)[0]
|
||||
for spacing in (FC_MONO, FC_DUAL):
|
||||
possibility = fc_match(family, False, False, spacing)
|
||||
for key, map_key in (('postscript_name', 'ps_map'), ('full_name', 'full_map'), ('family', 'family_map')):
|
||||
val = possibility.get(key)
|
||||
if val:
|
||||
candidates = font_map[map_key].get(family_name_to_key(val))
|
||||
if candidates:
|
||||
if len(candidates) == 1:
|
||||
# happens if the family name is an alias, so we search with
|
||||
# the actual family name to see if we can find all the
|
||||
# fonts in the family.
|
||||
family_name_candidates = font_map['family_map'].get(family_name_to_key(candidates[0]['family']))
|
||||
if family_name_candidates and len(family_name_candidates) > 1:
|
||||
candidates = family_name_candidates
|
||||
return sorted(candidates, key=score)[0]
|
||||
|
||||
# Use fc-match with a generic family
|
||||
family = 'monospace' if monospaced else 'sans-serif'
|
||||
|
|
|
|||
Loading…
Reference in a new issue