Render private use unicode characters that are followed by a space as two cell ligatures. Fixes #357

This commit is contained in:
Kovid Goyal 2018-03-04 22:58:24 +05:30
parent e716f6d35e
commit 97e1ecabdc
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 32 additions and 7 deletions

View File

@ -452,11 +452,9 @@ Some programs, like powerline, vim with fancy gutter symbols/status-bar, etc.
use unicode characters from the private use area to represent symbols. Often
these symbols are square and should be rendered in two cells. However, since
private use area symbols all have their width set to one in the unicode
standard, kitty renders them either smaller or truncated. The correct solution
for this is to use either use different symbols that are not square, or to use
a font that defines ligatures with the space character for these symbols. See
link:https://github.com/kovidgoyal/kitty/issues/182[#182] for a discussion of
the approach using ligatures.
standard, kitty renders them either smaller or truncated. The exception (as of
kitty 0.8.1) is if these characters are followed by a space or empty cell in
which case kitty makes use of the extra cell to render them in two cells.
=== How do I build kitty.app on macOS?

View File

@ -794,6 +794,17 @@ shape_run(Cell *first_cell, index_type num_cells, Font *font) {
#undef MAX_GLYPHS_IN_GROUP
}
static inline void
merge_groups_for_pua_space_ligature() {
if (G(group_idx) == 1) {
Group *g = G(groups), *g1 = G(groups) + 1;
g->num_cells += g1->num_cells;
g->num_glyphs += g1->num_glyphs;
g->num_glyphs = MIN(g->num_glyphs, MAX_NUM_EXTRA_GLYPHS + 1);
G(group_idx) = 0;
}
}
static inline void
render_groups(Font *font) {
unsigned idx = 0;
@ -847,10 +858,11 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
#undef G
static inline void
render_run(Cell *first_cell, index_type num_cells, ssize_t font_idx) {
render_run(Cell *first_cell, index_type num_cells, ssize_t font_idx, bool pua_space_ligature) {
switch(font_idx) {
default:
shape_run(first_cell, num_cells, &fonts.fonts[font_idx]);
if (pua_space_ligature) merge_groups_for_pua_space_ligature();
render_groups(&fonts.fonts[font_idx]);
break;
case BLANK_FONT:
@ -865,9 +877,14 @@ render_run(Cell *first_cell, index_type num_cells, ssize_t font_idx) {
}
}
static inline bool
is_private_use(char_type ch) {
return (0xe000 <= ch && ch <= 0xf8ff) || (0xF0000 <= ch && ch <= 0xFFFFF) || (0x100000 <= ch && ch <= 0x10FFFF);
}
void
render_line(Line *line) {
#define RENDER if (run_font_idx != NO_FONT && i > first_cell_in_run) render_run(line->cells + first_cell_in_run, i - first_cell_in_run, run_font_idx);
#define RENDER if (run_font_idx != NO_FONT && i > first_cell_in_run) render_run(line->cells + first_cell_in_run, i - first_cell_in_run, run_font_idx, false);
ssize_t run_font_idx = NO_FONT;
index_type first_cell_in_run, i;
attrs_type prev_width = 0;
@ -875,6 +892,16 @@ render_line(Line *line) {
if (prev_width == 2) { prev_width = 0; continue; }
Cell *cell = line->cells + i;
ssize_t cell_font_idx = font_for_cell(cell);
if (is_private_use(cell->ch) && i + 1 < line->xnum && (line->cells[i+1].ch == ' ' || line->cells[i+1].ch == 0) && cell_font_idx != BOX_FONT && cell_font_idx != MISSING_FONT) {
// We have a private use char followed by a space char, render it as a two cell ligature.
RENDER;
render_run(line->cells + i, 2, cell_font_idx, true);
run_font_idx = NO_FONT;
first_cell_in_run = i + 2;
prev_width = line->cells[i+1].attrs & WIDTH_MASK;
i++;
continue;
}
prev_width = cell->attrs & WIDTH_MASK;
if (run_font_idx == NO_FONT) run_font_idx = cell_font_idx;
if (run_font_idx == cell_font_idx) continue;