Merge branch 'no_ligatures_under_cursor' of https://github.com/Luflosi/kitty
This commit is contained in:
commit
493892a4df
@ -256,6 +256,11 @@ Syntax is::
|
||||
|
||||
'''))
|
||||
|
||||
o('disable_ligatures_under_cursor', False, long_text=_('''
|
||||
Render the characters of a ligature under the cursor individually
|
||||
to make editing more intuitive.
|
||||
'''))
|
||||
|
||||
|
||||
def box_drawing_scale(x):
|
||||
ans = tuple(float(x.strip()) for x in x.split(','))
|
||||
|
||||
@ -58,6 +58,7 @@ typedef struct {
|
||||
|
||||
|
||||
static hb_buffer_t *harfbuzz_buffer = NULL;
|
||||
static hb_feature_t no_liga_feature;
|
||||
static char_type shape_buffer[4096] = {0};
|
||||
static size_t max_texture_size = 1024, max_array_len = 1024;
|
||||
|
||||
@ -717,7 +718,7 @@ num_codepoints_in_cell(CPUCell *cell) {
|
||||
}
|
||||
|
||||
static inline void
|
||||
shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb_font_t *font) {
|
||||
shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb_font_t *font, bool disable_ligature) {
|
||||
if (group_state.groups_capacity <= 2 * num_cells) {
|
||||
group_state.groups_capacity = MAX(128, 2 * num_cells); // avoid unnecessary reallocs
|
||||
group_state.groups = realloc(group_state.groups, sizeof(Group) * group_state.groups_capacity);
|
||||
@ -741,7 +742,13 @@ shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb
|
||||
group_state.last_cpu_cell = first_cpu_cell + (num_cells ? num_cells - 1 : 0);
|
||||
group_state.last_gpu_cell = first_gpu_cell + (num_cells ? num_cells - 1 : 0);
|
||||
load_hb_buffer(first_cpu_cell, first_gpu_cell, num_cells);
|
||||
hb_shape(font, harfbuzz_buffer, NULL, 0);
|
||||
|
||||
if (!disable_ligature) {
|
||||
hb_shape(font, harfbuzz_buffer, NULL, 0);
|
||||
} else {
|
||||
hb_shape(font, harfbuzz_buffer, &no_liga_feature, 1);
|
||||
}
|
||||
|
||||
unsigned int info_length, positions_length;
|
||||
group_state.info = hb_buffer_get_glyph_infos(harfbuzz_buffer, &info_length);
|
||||
group_state.positions = hb_buffer_get_glyph_positions(harfbuzz_buffer, &positions_length);
|
||||
@ -806,8 +813,8 @@ check_cell_consumed(CellData *cell_data, CPUCell *last_cpu_cell) {
|
||||
|
||||
|
||||
static inline void
|
||||
shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, Font *font) {
|
||||
shape(first_cpu_cell, first_gpu_cell, num_cells, harfbuzz_font_for_face(font->face));
|
||||
shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, Font *font, bool disable_ligature) {
|
||||
shape(first_cpu_cell, first_gpu_cell, num_cells, harfbuzz_font_for_face(font->face), disable_ligature);
|
||||
#if 0
|
||||
// You can also generate this easily using hb-shape --show-extents --cluster-level=1 --shapers=ot /path/to/font/file text
|
||||
hb_buffer_serialize_glyphs(harfbuzz_buffer, 0, group_state.num_glyphs, (char*)canvas, sizeof(pixel) * CELLS_IN_CANVAS * cell_width * cell_height, NULL, harfbuzz_font_for_face(font->face), HB_BUFFER_SERIALIZE_FORMAT_TEXT, HB_BUFFER_SERIALIZE_FLAG_DEFAULT | HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS);
|
||||
@ -968,7 +975,7 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
|
||||
FontGroup *fg = font_groups;
|
||||
font = fg->fonts + fg->medium_font_idx;
|
||||
}
|
||||
shape_run(line->cpu_cells, line->gpu_cells, num, font);
|
||||
shape_run(line->cpu_cells, line->gpu_cells, num, font, false);
|
||||
|
||||
PyObject *ans = PyList_New(0);
|
||||
unsigned int idx = 0;
|
||||
@ -989,10 +996,10 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
|
||||
#undef G
|
||||
|
||||
static inline void
|
||||
render_run(FontGroup *fg, CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, ssize_t font_idx, bool pua_space_ligature, bool center_glyph) {
|
||||
render_run(FontGroup *fg, CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, ssize_t font_idx, bool pua_space_ligature, bool center_glyph, bool disable_ligature) {
|
||||
switch(font_idx) {
|
||||
default:
|
||||
shape_run(first_cpu_cell, first_gpu_cell, num_cells, &fg->fonts[font_idx]);
|
||||
shape_run(first_cpu_cell, first_gpu_cell, num_cells, &fg->fonts[font_idx], disable_ligature);
|
||||
if (pua_space_ligature) merge_groups_for_pua_space_ligature();
|
||||
render_groups(fg, &fg->fonts[font_idx], center_glyph);
|
||||
break;
|
||||
@ -1009,14 +1016,21 @@ render_run(FontGroup *fg, CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, inde
|
||||
}
|
||||
|
||||
void
|
||||
render_line(FONTS_DATA_HANDLE fg_, Line *line) {
|
||||
#define RENDER if (run_font_idx != NO_FONT && i > first_cell_in_run) render_run(fg, line->cpu_cells + first_cell_in_run, line->gpu_cells + first_cell_in_run, i - first_cell_in_run, run_font_idx, false, center_glyph);
|
||||
render_line(FONTS_DATA_HANDLE fg_, Line *line, index_type lnum, Cursor *cursor) {
|
||||
#define RENDER if (run_font_idx != NO_FONT && i > first_cell_in_run) { render_run(fg, line->cpu_cells + first_cell_in_run, line->gpu_cells + first_cell_in_run, i - first_cell_in_run, run_font_idx, false, center_glyph, disable_ligature); }
|
||||
FontGroup *fg = (FontGroup*)fg_;
|
||||
ssize_t run_font_idx = NO_FONT;
|
||||
bool center_glyph = false;
|
||||
index_type first_cell_in_run, i;
|
||||
bool disable_ligature = false;
|
||||
bool disable_ligature_in_line = false;
|
||||
index_type first_cell_in_run, i, cursor_x;
|
||||
attrs_type prev_width = 0;
|
||||
if (cursor != NULL && OPT(disable_ligatures_under_cursor)) {
|
||||
cursor_x = cursor->x;
|
||||
if (lnum == cursor->y) disable_ligature_in_line = true;
|
||||
}
|
||||
for (i=0, first_cell_in_run=0; i < line->xnum; i++) {
|
||||
disable_ligature = disable_ligature_in_line && (first_cell_in_run <= cursor_x && cursor_x <= i);
|
||||
if (prev_width == 2) { prev_width = 0; continue; }
|
||||
CPUCell *cpu_cell = line->cpu_cells + i;
|
||||
GPUCell *gpu_cell = line->gpu_cells + i;
|
||||
@ -1053,7 +1067,7 @@ render_line(FONTS_DATA_HANDLE fg_, Line *line) {
|
||||
center_glyph = true;
|
||||
RENDER
|
||||
center_glyph = false;
|
||||
render_run(fg, line->cpu_cells + i, line->gpu_cells + i, num_spaces + 1, cell_font_idx, true, center_glyph);
|
||||
render_run(fg, line->cpu_cells + i, line->gpu_cells + i, num_spaces + 1, cell_font_idx, true, center_glyph, disable_ligature);
|
||||
run_font_idx = NO_FONT;
|
||||
first_cell_in_run = i + num_spaces + 1;
|
||||
prev_width = line->gpu_cells[i+num_spaces].attrs & WIDTH_MASK;
|
||||
@ -1245,7 +1259,7 @@ test_render_line(PyObject UNUSED *self, PyObject *args) {
|
||||
PyObject *line;
|
||||
if (!PyArg_ParseTuple(args, "O!", &Line_Type, &line)) return NULL;
|
||||
if (!num_font_groups) { PyErr_SetString(PyExc_RuntimeError, "must create font group first"); return NULL; }
|
||||
render_line((FONTS_DATA_HANDLE)font_groups, (Line*)line);
|
||||
render_line((FONTS_DATA_HANDLE)font_groups, (Line*)line, 0, NULL);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@ -1367,6 +1381,8 @@ init_fonts(PyObject *module) {
|
||||
harfbuzz_buffer = hb_buffer_create();
|
||||
if (harfbuzz_buffer == NULL || !hb_buffer_allocation_successful(harfbuzz_buffer) || !hb_buffer_pre_allocate(harfbuzz_buffer, 2048)) { PyErr_NoMemory(); return false; }
|
||||
hb_buffer_set_cluster_level(harfbuzz_buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
|
||||
const char* feature_str = "-calt";
|
||||
if (!hb_feature_from_string(feature_str, strlen(feature_str), &no_liga_feature)) fatal("hb_feature_from_string() failed");
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
current_send_sprite_to_gpu = send_sprite_to_gpu;
|
||||
return true;
|
||||
|
||||
@ -34,7 +34,7 @@ PyObject* face_from_descriptor(PyObject*, FONTS_DATA_HANDLE);
|
||||
|
||||
void sprite_tracker_current_layout(FONTS_DATA_HANDLE data, unsigned int *x, unsigned int *y, unsigned int *z);
|
||||
void render_alpha_mask(uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *dest_rect, size_t src_stride, size_t dest_stride);
|
||||
void render_line(FONTS_DATA_HANDLE, Line *line);
|
||||
void render_line(FONTS_DATA_HANDLE, Line *line, index_type lnum, Cursor *cursor);
|
||||
void sprite_tracker_set_limits(size_t max_texture_size, size_t max_array_len);
|
||||
typedef void (*free_extra_data_func)(void*);
|
||||
StringCanvas render_simple_text_impl(PyObject *s, const char *text, unsigned int baseline);
|
||||
|
||||
@ -1468,7 +1468,7 @@ screen_reset_dirty(Screen *self) {
|
||||
}
|
||||
|
||||
void
|
||||
screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_data) {
|
||||
screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_data, bool update_cursor_pos) {
|
||||
unsigned int history_line_added_count = self->history_line_added_count;
|
||||
index_type lnum;
|
||||
bool was_dirty = self->is_dirty;
|
||||
@ -1478,8 +1478,9 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat
|
||||
for (index_type y = 0; y < MIN(self->lines, self->scrolled_by); y++) {
|
||||
lnum = self->scrolled_by - 1 - y;
|
||||
historybuf_init_line(self->historybuf, lnum, self->historybuf->line);
|
||||
if (self->historybuf->line->has_dirty_text) {
|
||||
render_line(fonts_data, self->historybuf->line);
|
||||
if (self->historybuf->line->has_dirty_text ||
|
||||
(update_cursor_pos && (self->cursor->y == lnum || self->last_rendered_cursor_y == lnum))) {
|
||||
render_line(fonts_data, self->historybuf->line, lnum, self->cursor);
|
||||
historybuf_mark_line_clean(self->historybuf, lnum);
|
||||
}
|
||||
update_line_data(self->historybuf->line, y, address);
|
||||
@ -1487,8 +1488,9 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat
|
||||
for (index_type y = self->scrolled_by; y < self->lines; y++) {
|
||||
lnum = y - self->scrolled_by;
|
||||
linebuf_init_line(self->linebuf, lnum);
|
||||
if (self->linebuf->line->has_dirty_text) {
|
||||
render_line(fonts_data, self->linebuf->line);
|
||||
if (self->linebuf->line->has_dirty_text ||
|
||||
(update_cursor_pos && (self->cursor->y == lnum || self->last_rendered_cursor_y == lnum))) {
|
||||
render_line(fonts_data, self->linebuf->line, lnum, self->cursor);
|
||||
linebuf_mark_line_clean(self->linebuf, lnum);
|
||||
}
|
||||
update_line_data(self->linebuf->line, y, address);
|
||||
|
||||
@ -65,6 +65,7 @@ typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
unsigned int columns, lines, margin_top, margin_bottom, charset, scrolled_by, last_selection_scrolled_by;
|
||||
unsigned int last_rendered_cursor_x, last_rendered_cursor_y;
|
||||
CellPixelSize cell_size;
|
||||
OverlayLine overlay_line;
|
||||
id_type window_id;
|
||||
@ -176,7 +177,7 @@ void screen_apply_selection(Screen *self, void *address, size_t size);
|
||||
bool screen_is_selection_dirty(Screen *self);
|
||||
bool screen_has_selection(Screen*);
|
||||
bool screen_invert_colors(Screen *self);
|
||||
void screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE);
|
||||
void screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE, bool update_cursor_pos);
|
||||
bool screen_is_cursor_visible(Screen *self);
|
||||
bool screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end);
|
||||
bool screen_selection_range_for_word(Screen *self, index_type x, index_type *, index_type *, index_type *start, index_type *end);
|
||||
|
||||
@ -286,14 +286,22 @@ cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloa
|
||||
|
||||
ensure_sprite_map(fonts_data);
|
||||
|
||||
if (screen->scroll_changed || screen->is_dirty) {
|
||||
bool cursor_pos_changed = screen->cursor->x != screen->last_rendered_cursor_x
|
||||
|| screen->cursor->y != screen->last_rendered_cursor_y;
|
||||
|
||||
if (screen->scroll_changed || screen->is_dirty || (OPT(disable_ligatures_under_cursor) && cursor_pos_changed)) {
|
||||
sz = sizeof(GPUCell) * screen->lines * screen->columns;
|
||||
address = alloc_and_map_vao_buffer(vao_idx, sz, cell_data_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY);
|
||||
screen_update_cell_data(screen, address, fonts_data);
|
||||
screen_update_cell_data(screen, address, fonts_data, OPT(disable_ligatures_under_cursor) && cursor_pos_changed);
|
||||
unmap_vao_buffer(vao_idx, cell_data_buffer); address = NULL;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (cursor_pos_changed) {
|
||||
screen->last_rendered_cursor_x = screen->cursor->x;
|
||||
screen->last_rendered_cursor_y = screen->cursor->y;
|
||||
}
|
||||
|
||||
if (screen_is_selection_dirty(screen)) {
|
||||
sz = screen->lines * screen->columns;
|
||||
address = alloc_and_map_vao_buffer(vao_idx, sz, selection_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY);
|
||||
|
||||
@ -403,6 +403,7 @@ PYWRAP1(set_options) {
|
||||
S(macos_hide_from_tasks, PyObject_IsTrue);
|
||||
S(macos_thicken_font, PyFloat_AsDouble);
|
||||
S(tab_bar_min_tabs, PyLong_AsUnsignedLong);
|
||||
S(disable_ligatures_under_cursor, PyObject_IsTrue);
|
||||
|
||||
GA(tab_bar_style);
|
||||
global_state.tab_bar_hidden = PyUnicode_CompareWithASCIIString(ret, "hidden") == 0 ? true: false;
|
||||
|
||||
@ -35,6 +35,7 @@ typedef struct {
|
||||
float window_padding_width;
|
||||
Edge tab_bar_edge;
|
||||
unsigned long tab_bar_min_tabs;
|
||||
bool disable_ligatures_under_cursor;
|
||||
bool sync_to_monitor;
|
||||
bool close_on_child_death;
|
||||
bool window_alert_on_bell;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user