Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d2a720fb9 | ||
|
|
9ed980a511 | ||
|
|
1365eafce5 | ||
|
|
07b70f8c95 | ||
|
|
f16bf2a136 | ||
|
|
0f2bcfabb3 | ||
|
|
d3e8c616b0 | ||
|
|
99888996a0 | ||
|
|
4c94e16936 | ||
|
|
235f3940f2 | ||
|
|
e86c2f2000 | ||
|
|
65b212fa1b | ||
|
|
4b0ff03868 | ||
|
|
8961eaaa9d | ||
|
|
356722b9a6 | ||
|
|
89e5ae28bb | ||
|
|
b40e1e6492 | ||
|
|
4dc6918b13 |
@@ -3,6 +3,23 @@ Changelog
|
||||
|
||||
kitty is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||
|
||||
version 0.5.1 [2017-12-01]
|
||||
---------------------------
|
||||
|
||||
- Add an option to control the thickness of lines in box drawing characters
|
||||
|
||||
- Increase max. allowed ligature length to nine characters
|
||||
|
||||
- Fix text not vertically centered when adjusting line height
|
||||
|
||||
- Fix unicode block characters not being rendered properly
|
||||
|
||||
- Fix shift+up/down not generating correct escape codes
|
||||
|
||||
- Image display: Fix displaying images taller than two screen heights not
|
||||
scrolling properly
|
||||
|
||||
|
||||
version 0.5.0 [2017-11-19]
|
||||
---------------------------
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from .fast_data_types import (
|
||||
destroy_sprite_map, glfw_post_empty_event, layout_sprite_map
|
||||
)
|
||||
from .fonts.render import prerender, resize_fonts, set_font_family
|
||||
from .keys import get_key_map, get_sent_data, get_shortcut
|
||||
from .keys import get_key_map, get_shortcut
|
||||
from .session import create_session
|
||||
from .tabs import SpecialWindow, TabManager
|
||||
from .utils import (
|
||||
@@ -199,13 +199,6 @@ class Boss:
|
||||
passthrough = f(*key_action.args)
|
||||
if passthrough is not True:
|
||||
return True
|
||||
key, scancode, action, mods = self.current_key_press_info
|
||||
data = get_sent_data(
|
||||
self.opts.send_text_map, key, scancode, mods, window, action
|
||||
)
|
||||
if data:
|
||||
window.write_to_child(data)
|
||||
return True
|
||||
return False
|
||||
|
||||
def combine(self, *actions):
|
||||
|
||||
@@ -391,7 +391,7 @@ resize_pty(ChildMonitor *self, PyObject *args) {
|
||||
if (fd == -1) FIND(add_queue, add_queue_count);
|
||||
if (fd != -1) {
|
||||
if (!pty_resize(fd, &dim)) PyErr_SetFromErrno(PyExc_OSError);
|
||||
} else fprintf(stderr, "Failed to send resize signal to child with id: %lu (children count: %u) (add queue: %lu)\n", window_id, self->count, add_queue_count);
|
||||
} else fprintf(stderr, "Failed to send resize signal to child with id: %lu (children count: %u) (add queue: %zu)\n", window_id, self->count, add_queue_count);
|
||||
children_mutex(unlock);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
Py_RETURN_NONE;
|
||||
|
||||
@@ -19,7 +19,7 @@ from .rgb import to_color
|
||||
from .utils import safe_print
|
||||
|
||||
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
|
||||
MINIMUM_FONT_SIZE = 6
|
||||
MINIMUM_FONT_SIZE = 4
|
||||
|
||||
|
||||
def to_font_size(x):
|
||||
@@ -175,7 +175,7 @@ def parse_send_text_bytes(text):
|
||||
return ast.literal_eval("'''" + text + "'''").encode('utf-8')
|
||||
|
||||
|
||||
def parse_send_text(val):
|
||||
def parse_send_text(val, keymap):
|
||||
parts = val.split(' ')
|
||||
|
||||
def abort(msg):
|
||||
@@ -187,28 +187,10 @@ def parse_send_text(val):
|
||||
|
||||
if len(parts) < 3:
|
||||
return abort('Incomplete')
|
||||
|
||||
text = ' '.join(parts[2:])
|
||||
mode, sc = parts[:2]
|
||||
mods, key = parse_shortcut(sc.strip())
|
||||
if key is None:
|
||||
return abort('Invalid shortcut')
|
||||
text = parse_send_text_bytes(text)
|
||||
if not text:
|
||||
return abort('Empty text')
|
||||
|
||||
if mode in ('all', '*'):
|
||||
modes = parse_send_text.all_modes
|
||||
else:
|
||||
modes = frozenset(mode.split(',')).intersection(
|
||||
parse_send_text.all_modes
|
||||
)
|
||||
if not modes:
|
||||
return abort('Invalid keyboard modes')
|
||||
return {mode: {(mods, key): text} for mode in modes}
|
||||
|
||||
|
||||
parse_send_text.all_modes = frozenset({'normal', 'application', 'kitty'})
|
||||
text = ' '.join(parts[2:])
|
||||
key_str = '{} send_text {} {}'.format(sc, mode, text)
|
||||
return parse_key(key_str, keymap)
|
||||
|
||||
|
||||
def to_open_url_modifiers(val):
|
||||
@@ -238,6 +220,13 @@ def adjust_line_height(x):
|
||||
return int(x)
|
||||
|
||||
|
||||
def box_drawing_scale(x):
|
||||
ans = tuple(float(x.strip()) for x in x.split(','))
|
||||
if len(ans) != 4:
|
||||
raise ValueError('Invalid box_drawing scale, must have four entries')
|
||||
return ans
|
||||
|
||||
|
||||
type_map = {
|
||||
'adjust_line_height': adjust_line_height,
|
||||
'scrollback_lines': positive_int,
|
||||
@@ -267,6 +256,7 @@ type_map = {
|
||||
'use_system_wcwidth': to_bool,
|
||||
'macos_hide_titlebar': to_bool,
|
||||
'macos_option_as_alt': to_bool,
|
||||
'box_drawing_scale': box_drawing_scale,
|
||||
}
|
||||
|
||||
for name in (
|
||||
@@ -285,11 +275,6 @@ def parse_config(lines, check_keys=True):
|
||||
ans = {
|
||||
'keymap': {},
|
||||
'symbol_map': {},
|
||||
'send_text_map': {
|
||||
'kitty': {},
|
||||
'normal': {},
|
||||
'application': {}
|
||||
}
|
||||
}
|
||||
if check_keys:
|
||||
all_keys = defaults._asdict()
|
||||
@@ -307,9 +292,8 @@ def parse_config(lines, check_keys=True):
|
||||
ans['symbol_map'].update(parse_symbol_map(val))
|
||||
continue
|
||||
if key == 'send_text':
|
||||
stvals = parse_send_text(val)
|
||||
for k, v in ans['send_text_map'].items():
|
||||
v.update(stvals.get(k, {}))
|
||||
# For legacy compatibility
|
||||
parse_send_text(val, ans['keymap'])
|
||||
continue
|
||||
if check_keys:
|
||||
if key not in all_keys:
|
||||
@@ -360,11 +344,6 @@ def merge_configs(defaults, vals):
|
||||
newvals = vals.get(k, {})
|
||||
if k == 'keymap':
|
||||
ans['keymap'] = merge_keymaps(v, newvals)
|
||||
elif k == 'send_text_map':
|
||||
ans[k] = {
|
||||
m: merge_dicts(mm, newvals.get(m, {}))
|
||||
for m, mm in v.items()
|
||||
}
|
||||
else:
|
||||
ans[k] = merge_dicts(v, newvals)
|
||||
else:
|
||||
|
||||
@@ -11,7 +11,7 @@ from collections import namedtuple
|
||||
from .fast_data_types import set_boss as set_c_boss
|
||||
|
||||
appname = 'kitty'
|
||||
version = (0, 5, 0)
|
||||
version = (0, 5, 1)
|
||||
str_version = '.'.join(map(str, version))
|
||||
_plat = sys.platform.lower()
|
||||
isosx = 'darwin' in _plat
|
||||
@@ -67,7 +67,11 @@ cell_size = ViewportSize()
|
||||
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
terminfo_dir = os.path.join(base_dir, 'terminfo')
|
||||
logo_data_file = os.path.join(base_dir, 'logo', 'kitty.rgba')
|
||||
shell_path = pwd.getpwuid(os.geteuid()).pw_shell or '/bin/sh'
|
||||
try:
|
||||
shell_path = pwd.getpwuid(os.geteuid()).pw_shell or '/bin/sh'
|
||||
except KeyError:
|
||||
print('Failed to read login shell from /etc/passwd for current user, falling back to /bin/sh', file=sys.stderr)
|
||||
shell_path = '/bin/sh'
|
||||
|
||||
GLint = ctypes.c_int if ctypes.sizeof(ctypes.c_int) == 4 else ctypes.c_long
|
||||
GLuint = ctypes.c_uint if ctypes.sizeof(ctypes.c_uint) == 4 else ctypes.c_ulong
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "state.h"
|
||||
|
||||
#define MISSING_GLYPH 4
|
||||
#define MAX_NUM_EXTRA_GLYPHS 8
|
||||
|
||||
typedef uint16_t glyph_index;
|
||||
typedef void (*send_sprite_to_gpu_func)(unsigned int, unsigned int, unsigned int, uint8_t*);
|
||||
@@ -21,13 +22,17 @@ typedef struct SpecialGlyphCache SpecialGlyphCache;
|
||||
enum {NO_FONT=-3, MISSING_FONT=-2, BLANK_FONT=-1, BOX_FONT=0};
|
||||
|
||||
|
||||
typedef struct {
|
||||
glyph_index data[MAX_NUM_EXTRA_GLYPHS];
|
||||
} ExtraGlyphs;
|
||||
|
||||
struct SpritePosition {
|
||||
SpritePosition *next;
|
||||
bool filled, rendered;
|
||||
sprite_index x, y, z;
|
||||
uint8_t ligature_index;
|
||||
glyph_index glyph;
|
||||
uint64_t extra_glyphs;
|
||||
ExtraGlyphs extra_glyphs;
|
||||
};
|
||||
|
||||
struct SpecialGlyphCache {
|
||||
@@ -70,6 +75,7 @@ typedef struct {
|
||||
|
||||
static Fonts fonts = {0};
|
||||
|
||||
|
||||
// Sprites {{{
|
||||
|
||||
static inline void
|
||||
@@ -104,15 +110,25 @@ do_increment(int *error) {
|
||||
}
|
||||
|
||||
|
||||
static inline bool
|
||||
extra_glyphs_equal(ExtraGlyphs *a, ExtraGlyphs *b) {
|
||||
for (size_t i = 0; i < MAX_NUM_EXTRA_GLYPHS; i++) {
|
||||
if (a->data[i] != b->data[i]) return false;
|
||||
if (a->data[i] == 0) return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static SpritePosition*
|
||||
sprite_position_for(Font *font, glyph_index glyph, uint64_t extra_glyphs, uint8_t ligature_index, int *error) {
|
||||
sprite_position_for(Font *font, glyph_index glyph, ExtraGlyphs *extra_glyphs, uint8_t ligature_index, int *error) {
|
||||
glyph_index idx = glyph & 0x3ff;
|
||||
SpritePosition *s = font->sprite_map + idx;
|
||||
// Optimize for the common case of glyph under 1024 already in the cache
|
||||
if (LIKELY(s->glyph == glyph && s->filled && s->extra_glyphs == extra_glyphs && s->ligature_index == ligature_index)) return s; // Cache hit
|
||||
if (LIKELY(s->glyph == glyph && s->filled && extra_glyphs_equal(&s->extra_glyphs, extra_glyphs) && s->ligature_index == ligature_index)) return s; // Cache hit
|
||||
while(true) {
|
||||
if (s->filled) {
|
||||
if (s->glyph == glyph && s->extra_glyphs == extra_glyphs && s->ligature_index == ligature_index) return s; // Cache hit
|
||||
if (s->glyph == glyph && extra_glyphs_equal(&s->extra_glyphs, extra_glyphs) && s->ligature_index == ligature_index) return s; // Cache hit
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -123,7 +139,7 @@ sprite_position_for(Font *font, glyph_index glyph, uint64_t extra_glyphs, uint8_
|
||||
s = s->next;
|
||||
}
|
||||
s->glyph = glyph;
|
||||
s->extra_glyphs = extra_glyphs;
|
||||
memcpy(&s->extra_glyphs, extra_glyphs, sizeof(ExtraGlyphs));
|
||||
s->ligature_index = ligature_index;
|
||||
s->filled = true;
|
||||
s->rendered = false;
|
||||
@@ -179,7 +195,7 @@ free_maps(Font *font) {
|
||||
|
||||
void
|
||||
clear_sprite_map(Font *font) {
|
||||
#define CLEAR(s) s->filled = false; s->rendered = false; s->glyph = 0; s->extra_glyphs = 0; s->x = 0; s->y = 0; s->z = 0; s->ligature_index = 0;
|
||||
#define CLEAR(s) s->filled = false; s->rendered = false; s->glyph = 0; memset(&s->extra_glyphs, 0, sizeof(ExtraGlyphs)); s->x = 0; s->y = 0; s->z = 0; s->ligature_index = 0;
|
||||
SpritePosition *s;
|
||||
for (size_t i = 0; i < sizeof(font->sprite_map)/sizeof(font->sprite_map[0]); i++) {
|
||||
s = font->sprite_map + i;
|
||||
@@ -246,7 +262,7 @@ del_font(Font *f) {
|
||||
|
||||
static unsigned int cell_width = 0, cell_height = 0, baseline = 0, underline_position = 0, underline_thickness = 0;
|
||||
static uint8_t *canvas = NULL;
|
||||
#define CELLS_IN_CANVAS 16
|
||||
#define CELLS_IN_CANVAS ((MAX_NUM_EXTRA_GLYPHS + 1) * 3)
|
||||
static inline void
|
||||
clear_canvas(void) { memset(canvas, 0, CELLS_IN_CANVAS * cell_width * cell_height); }
|
||||
|
||||
@@ -267,11 +283,17 @@ update_cell_metrics() {
|
||||
CALL(fonts.bold_font_idx, 0, false); CALL(fonts.italic_font_idx, 0, false); CALL(fonts.bi_font_idx, 0, false);
|
||||
cell_metrics(fonts.fonts[fonts.medium_font_idx].face, &cell_width, &cell_height, &baseline, &underline_position, &underline_thickness);
|
||||
if (!cell_width) { PyErr_SetString(PyExc_ValueError, "Failed to calculate cell width for the specified font."); return NULL; }
|
||||
unsigned int before_cell_height = cell_height;
|
||||
if (OPT(adjust_line_height_px) != 0) cell_height += OPT(adjust_line_height_px);
|
||||
if (OPT(adjust_line_height_frac) != 0.f) cell_height *= OPT(adjust_line_height_frac);
|
||||
int line_height_adjustment = cell_height - before_cell_height;
|
||||
if (cell_height < 4) { PyErr_SetString(PyExc_ValueError, "line height too small after adjustment"); return NULL; }
|
||||
if (cell_height > 1000) { PyErr_SetString(PyExc_ValueError, "line height too large after adjustment"); return NULL; }
|
||||
underline_position = MIN(cell_height - 1, underline_position);
|
||||
if (line_height_adjustment > 1) {
|
||||
baseline += MIN(cell_height - 1, (unsigned)line_height_adjustment / 2);
|
||||
underline_position += MIN(cell_height - 1, (unsigned)line_height_adjustment / 2);
|
||||
}
|
||||
sprite_tracker_set_layout(cell_width, cell_height);
|
||||
global_state.cell_width = cell_width; global_state.cell_height = cell_height;
|
||||
free(canvas); canvas = malloc(CELLS_IN_CANVAS * cell_width * cell_height);
|
||||
@@ -360,7 +382,7 @@ START_ALLOW_CASE_RANGE
|
||||
case ' ':
|
||||
return BLANK_FONT;
|
||||
case 0x2500 ... 0x2570:
|
||||
case 0x2574 ... 0x257f:
|
||||
case 0x2574 ... 0x259f:
|
||||
case 0xe0b0:
|
||||
case 0xe0b2:
|
||||
return BOX_FONT;
|
||||
@@ -393,14 +415,14 @@ static inline glyph_index
|
||||
box_glyph_id(char_type ch) {
|
||||
START_ALLOW_CASE_RANGE
|
||||
switch(ch) {
|
||||
case 0x2500 ... 0x257f:
|
||||
case 0x2500 ... 0x259f:
|
||||
return ch - 0x2500;
|
||||
case 0xe0b0:
|
||||
return 0x80;
|
||||
return 0xfa;
|
||||
case 0xe0b2:
|
||||
return 0x81;
|
||||
return 0xfb;
|
||||
default:
|
||||
return 0x82;
|
||||
return 0xff;
|
||||
}
|
||||
END_ALLOW_CASE_RANGE
|
||||
}
|
||||
@@ -411,7 +433,8 @@ static void
|
||||
render_box_cell(Cell *cell) {
|
||||
int error = 0;
|
||||
glyph_index glyph = box_glyph_id(cell->ch);
|
||||
SpritePosition *sp = sprite_position_for(&fonts.fonts[BOX_FONT], glyph, 0, false, &error);
|
||||
static ExtraGlyphs extra_glyphs = {{0}};
|
||||
SpritePosition *sp = sprite_position_for(&fonts.fonts[BOX_FONT], glyph, &extra_glyphs, false, &error);
|
||||
if (sp == NULL) {
|
||||
sprite_map_set_error(error); PyErr_Print();
|
||||
set_sprite(cell, 0, 0, 0);
|
||||
@@ -462,7 +485,7 @@ extract_cell_from_canvas(unsigned int i, unsigned int num_cells) {
|
||||
}
|
||||
|
||||
static inline void
|
||||
render_group(unsigned int num_cells, unsigned int num_glyphs, Cell *cells, hb_glyph_info_t *info, hb_glyph_position_t *positions, Font *font, glyph_index glyph, uint64_t extra_glyphs) {
|
||||
render_group(unsigned int num_cells, unsigned int num_glyphs, Cell *cells, hb_glyph_info_t *info, hb_glyph_position_t *positions, Font *font, glyph_index glyph, ExtraGlyphs *extra_glyphs) {
|
||||
static SpritePosition* sprite_position[16];
|
||||
int error = 0;
|
||||
num_cells = MIN(sizeof(sprite_position)/sizeof(sprite_position[0]), num_cells);
|
||||
@@ -550,7 +573,7 @@ check_cell_consumed(CellData *cell_data, Cell *last_cell) {
|
||||
}
|
||||
|
||||
static inline glyph_index
|
||||
next_group(Font *font, unsigned int *num_group_cells, unsigned int *num_group_glyphs, Cell *cells, hb_glyph_info_t *info, unsigned int max_num_glyphs, unsigned int max_num_cells, uint64_t *extra_glyphs) {
|
||||
next_group(Font *font, unsigned int *num_group_cells, unsigned int *num_group_glyphs, Cell *cells, hb_glyph_info_t *info, unsigned int max_num_glyphs, unsigned int max_num_cells, ExtraGlyphs *extra_glyphs) {
|
||||
// See https://github.com/behdad/harfbuzz/issues/615 for a discussion of
|
||||
// how to break text into cells. In addition, we have to deal with
|
||||
// monospace ligature fonts that use dummy glyphs of zero size to implement
|
||||
@@ -558,7 +581,7 @@ next_group(Font *font, unsigned int *num_group_cells, unsigned int *num_group_gl
|
||||
|
||||
CellData cell_data;
|
||||
cell_data.cell = cells; cell_data.num_codepoints = num_codepoints_in_cell(cells); cell_data.codepoints_consumed = 0; cell_data.current_codepoint = cells->ch;
|
||||
#define LIMIT 5
|
||||
#define LIMIT (MAX_NUM_EXTRA_GLYPHS + 1)
|
||||
glyph_index glyphs_in_group[LIMIT];
|
||||
unsigned int ncells = 0, nglyphs = 0, n;
|
||||
uint32_t previous_cluster = UINT32_MAX, cluster;
|
||||
@@ -584,27 +607,16 @@ next_group(Font *font, unsigned int *num_group_cells, unsigned int *num_group_gl
|
||||
}
|
||||
*num_group_cells = MAX(1, MIN(ncells, cell_limit));
|
||||
*num_group_glyphs = MAX(1, MIN(nglyphs, glyph_limit));
|
||||
memset(extra_glyphs, 0, sizeof(ExtraGlyphs));
|
||||
|
||||
#define G(n) ((uint64_t)(glyphs_in_group[n] & 0xffff))
|
||||
switch(nglyphs) {
|
||||
case 0:
|
||||
case 1:
|
||||
*extra_glyphs = 0;
|
||||
break;
|
||||
case 2:
|
||||
*extra_glyphs = G(1);
|
||||
break;
|
||||
case 3:
|
||||
*extra_glyphs = G(1) | (G(2) << 16);
|
||||
break;
|
||||
case 4:
|
||||
*extra_glyphs = G(1) | (G(2) << 16) | (G(3) << 32);
|
||||
break;
|
||||
default: // we only support a maximum of four extra glyphs per cell
|
||||
*extra_glyphs = G(1) | (G(2) << 16) | (G(3) << 32) | (G(4) << 48);
|
||||
default:
|
||||
memcpy(&extra_glyphs->data, glyphs_in_group + 1, sizeof(glyph_index) * MIN(MAX_NUM_EXTRA_GLYPHS, nglyphs - 1));
|
||||
break;
|
||||
}
|
||||
#undef G
|
||||
#undef LIMIT
|
||||
return glyphs_in_group[0];
|
||||
}
|
||||
@@ -633,11 +645,12 @@ shape_run(Cell *first_cell, index_type num_cells, Font *font) {
|
||||
clear_canvas();
|
||||
#endif
|
||||
unsigned int run_pos = 0, cell_pos = 0, num_group_glyphs, num_group_cells;
|
||||
uint64_t extra_glyphs; glyph_index first_glyph;
|
||||
ExtraGlyphs extra_glyphs;
|
||||
glyph_index first_glyph;
|
||||
while(run_pos < num_glyphs && cell_pos < num_cells) {
|
||||
first_glyph = next_group(font, &num_group_cells, &num_group_glyphs, first_cell + cell_pos, info + run_pos, num_glyphs - run_pos, num_cells - cell_pos, &extra_glyphs);
|
||||
/* printf("Group: num_group_cells: %u num_group_glyphs: %u\n", num_group_cells, num_group_glyphs); */
|
||||
render_group(num_group_cells, num_group_glyphs, first_cell + cell_pos, info + run_pos, positions + run_pos, font, first_glyph, extra_glyphs);
|
||||
render_group(num_group_cells, num_group_glyphs, first_cell + cell_pos, info + run_pos, positions + run_pos, font, first_glyph, &extra_glyphs);
|
||||
run_pos += num_group_glyphs; cell_pos += num_group_cells;
|
||||
}
|
||||
}
|
||||
@@ -665,10 +678,13 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
|
||||
|
||||
PyObject *ans = PyList_New(0);
|
||||
unsigned int run_pos = 0, cell_pos = 0, num_group_glyphs, num_group_cells;
|
||||
uint64_t extra_glyphs; glyph_index first_glyph;
|
||||
ExtraGlyphs extra_glyphs;
|
||||
glyph_index first_glyph;
|
||||
while(run_pos < num_glyphs && cell_pos < num) {
|
||||
first_glyph = next_group(font, &num_group_cells, &num_group_glyphs, line->cells + cell_pos, info + run_pos, num_glyphs - run_pos, num - cell_pos, &extra_glyphs);
|
||||
PyList_Append(ans, Py_BuildValue("IIIK", num_group_cells, num_group_glyphs, first_glyph, extra_glyphs));
|
||||
PyObject *eg = PyTuple_New(MAX_NUM_EXTRA_GLYPHS);
|
||||
for (size_t g = 0; g < MAX_NUM_EXTRA_GLYPHS; g++) PyTuple_SET_ITEM(eg, g, Py_BuildValue("H", extra_glyphs.data[g]));
|
||||
PyList_Append(ans, Py_BuildValue("IIIN", num_group_cells, num_group_glyphs, first_glyph, eg));
|
||||
run_pos += num_group_glyphs; cell_pos += num_group_cells;
|
||||
}
|
||||
if (face) { Py_CLEAR(face); free(font); }
|
||||
@@ -778,10 +794,10 @@ sprite_map_set_layout(PyObject UNUSED *self, PyObject *args) {
|
||||
static PyObject*
|
||||
test_sprite_position_for(PyObject UNUSED *self, PyObject *args) {
|
||||
glyph_index glyph;
|
||||
uint64_t extra_glyphs = 0;
|
||||
if (!PyArg_ParseTuple(args, "H|I", &glyph, &extra_glyphs)) return NULL;
|
||||
ExtraGlyphs extra_glyphs = {{0}};
|
||||
if (!PyArg_ParseTuple(args, "H|I", &glyph, &extra_glyphs.data)) return NULL;
|
||||
int error;
|
||||
SpritePosition *pos = sprite_position_for(&fonts.fonts[fonts.medium_font_idx], glyph, extra_glyphs, 0, &error);
|
||||
SpritePosition *pos = sprite_position_for(&fonts.fonts[fonts.medium_font_idx], glyph, &extra_glyphs, 0, &error);
|
||||
if (pos == NULL) { sprite_map_set_error(error); return NULL; }
|
||||
return Py_BuildValue("HHH", pos->x, pos->y, pos->z);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,23 @@
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import math
|
||||
import os
|
||||
from functools import partial as p
|
||||
from itertools import repeat
|
||||
|
||||
from kitty.utils import get_logical_dpi
|
||||
|
||||
scale = (0.001, 1, 1.5, 2)
|
||||
|
||||
|
||||
def set_scale(new_scale):
|
||||
global scale
|
||||
scale = tuple(new_scale)
|
||||
|
||||
|
||||
def thickness(level=1, horizontal=True):
|
||||
dpi = get_logical_dpi()[0 if horizontal else 1]
|
||||
pts = (0.001, 1, 1.5, 2)[level]
|
||||
pts = scale[level]
|
||||
return int(math.ceil(pts * dpi / 72.0))
|
||||
|
||||
|
||||
@@ -264,6 +272,49 @@ def inner_corner(buf, width, height, which='tl', level=1):
|
||||
draw_vline(buf, width, y1, y2, width // 2 + (xd * hgap), level)
|
||||
|
||||
|
||||
def vblock(buf, width, height, frac=1, gravity='top'):
|
||||
num_rows = min(height, round(frac * height))
|
||||
start = 0 if gravity == 'top' else height - num_rows
|
||||
for r in range(start, start + num_rows):
|
||||
off = r * width
|
||||
for c in range(off, off + width):
|
||||
buf[c] = 255
|
||||
|
||||
|
||||
def hblock(buf, width, height, frac=1, gravity='left'):
|
||||
num_cols = min(width, round(frac * width))
|
||||
start = 0 if gravity == 'left' else width - num_cols
|
||||
for r in range(height):
|
||||
off = r * width + start
|
||||
for c in range(off, off + num_cols):
|
||||
buf[c] = 255
|
||||
|
||||
|
||||
def shade(buf, width, height, frac=1/4):
|
||||
rand = bytearray(os.urandom(width * height))
|
||||
cutoff = int(frac * 255)
|
||||
|
||||
for r in range(height):
|
||||
off = width * r
|
||||
for c in range(width):
|
||||
q = off + c
|
||||
if rand[q] < cutoff:
|
||||
buf[q] = 255
|
||||
|
||||
|
||||
def quad(buf, width, height, x=0, y=0):
|
||||
num_cols = width // 2
|
||||
left = x * num_cols
|
||||
right = width if x else num_cols
|
||||
num_rows = height // 2
|
||||
top = y * num_rows
|
||||
bottom = height if y else num_rows
|
||||
for r in range(top, bottom):
|
||||
off = r * width
|
||||
for c in range(left, right):
|
||||
buf[off + c] = 255
|
||||
|
||||
|
||||
box_chars = {
|
||||
'─': [hline],
|
||||
'━': [p(hline, level=3)],
|
||||
@@ -308,6 +359,38 @@ box_chars = {
|
||||
'╣': [p(inner_corner, which='tl'), p(inner_corner, which='bl'), p(dvline, only='right')],
|
||||
'╦': [p(inner_corner, which='bl'), p(inner_corner, which='br'), p(dhline, only='top')],
|
||||
'╩': [p(inner_corner, which='tl'), p(inner_corner, which='tr'), p(dhline, only='bottom')],
|
||||
'▀': [p(vblock, frac=1/2)],
|
||||
'▁': [p(vblock, frac=1/8, gravity='bottom')],
|
||||
'▂': [p(vblock, frac=1/4, gravity='bottom')],
|
||||
'▃': [p(vblock, frac=3/8, gravity='bottom')],
|
||||
'▄': [p(vblock, frac=1/2, gravity='bottom')],
|
||||
'▅': [p(vblock, frac=5/8, gravity='bottom')],
|
||||
'▆': [p(vblock, frac=3/4, gravity='bottom')],
|
||||
'▇': [p(vblock, frac=7/8, gravity='bottom')],
|
||||
'█': [p(vblock, frac=1, gravity='bottom')],
|
||||
'▉': [p(hblock, frac=7/8)],
|
||||
'▊': [p(hblock, frac=3/4)],
|
||||
'▋': [p(hblock, frac=5/8)],
|
||||
'▌': [p(hblock, frac=1/2)],
|
||||
'▍': [p(hblock, frac=3/8)],
|
||||
'▎': [p(hblock, frac=1/4)],
|
||||
'▏': [p(hblock, frac=1/8)],
|
||||
'▐': [p(hblock, frac=1/2, gravity='right')],
|
||||
'░': [p(shade, frac=1/4)],
|
||||
'▒': [p(shade, frac=2/4)],
|
||||
'▓': [p(shade, frac=3/4)],
|
||||
'▔': [p(vblock, frac=1/8)],
|
||||
'▕': [p(hblock, frac=1/8, gravity='right')],
|
||||
'▖': [p(quad, y=1)],
|
||||
'▗': [p(quad, x=1, y=1)],
|
||||
'▘': [quad],
|
||||
'▙': [quad, p(quad, y=1), p(quad, x=1, y=1)],
|
||||
'▚': [quad, p(quad, x=1, y=1)],
|
||||
'▛': [quad, p(quad, x=1), p(quad, y=1)],
|
||||
'▜': [quad, p(quad, x=1, y=1), p(quad, x=1)],
|
||||
'▝': [p(quad, x=1)],
|
||||
'▞': [p(quad, x=1), p(quad, y=1)],
|
||||
'▟': [p(quad, x=1), p(quad, y=1), p(quad, x=1, y=1)],
|
||||
}
|
||||
|
||||
t, f = 1, 3
|
||||
@@ -336,8 +419,6 @@ for chars, func in (('╒╕╘╛', dvcorner), ('╓╖╙╜', dhcorner), ('
|
||||
for ch in chars:
|
||||
box_chars[ch] = [p(func, which=ch)]
|
||||
|
||||
is_renderable_box_char = box_chars.__contains__
|
||||
|
||||
|
||||
def render_box_char(ch, buf, width, height):
|
||||
for func in box_chars[ch]:
|
||||
@@ -354,34 +435,41 @@ def render_missing_glyph(buf, width, height):
|
||||
draw_vline(buf, width, vgap, height - vgap + 1, width - hgap, 0)
|
||||
|
||||
|
||||
def join_rows(width, height, rows):
|
||||
import ctypes
|
||||
ans = (ctypes.c_ubyte * (width * height * len(rows)))()
|
||||
pos = ctypes.addressof(ans)
|
||||
row_sz = width * height
|
||||
for row in rows:
|
||||
ctypes.memmove(pos, ctypes.addressof(row), row_sz)
|
||||
pos += row_sz
|
||||
return ans
|
||||
|
||||
|
||||
def test_drawing(sz=32, family='monospace'):
|
||||
from .render import join_cells, display_bitmap, render_cell, set_font_family
|
||||
from kitty.config import defaults
|
||||
opts = defaults._replace(font_family=family, font_size=sz)
|
||||
width, height = set_font_family(opts)
|
||||
from .render import display_bitmap, setup_for_testing
|
||||
from kitty.fast_data_types import concat_cells, set_send_sprite_to_gpu
|
||||
|
||||
width, height = setup_for_testing(family, sz)[1:]
|
||||
space = bytearray(width * height)
|
||||
|
||||
def join_cells(cells):
|
||||
cells = tuple(bytes(x) for x in cells)
|
||||
return concat_cells(width, height, cells)
|
||||
|
||||
def render_chr(ch):
|
||||
if ch in box_chars:
|
||||
cell = bytearray(len(space))
|
||||
render_box_char(ch, cell, width, height)
|
||||
return cell
|
||||
return space
|
||||
|
||||
pos = 0x2500
|
||||
rows = []
|
||||
space = render_cell()[0]
|
||||
space_row = join_cells(width, height, *repeat(space, 32))
|
||||
space_row = join_cells(repeat(space, 32))
|
||||
|
||||
for r in range(8):
|
||||
row = []
|
||||
for i in range(16):
|
||||
row.append(render_cell(chr(pos))[0]), row.append(space)
|
||||
pos += 1
|
||||
rows.append(join_cells(width, height, *row))
|
||||
rows.append(space_row)
|
||||
width *= 32
|
||||
im = join_rows(width, height, rows)
|
||||
display_bitmap(im, width, height * len(rows))
|
||||
try:
|
||||
for r in range(10):
|
||||
row = []
|
||||
for i in range(16):
|
||||
row.append(render_chr(chr(pos)))
|
||||
row.append(space)
|
||||
pos += 1
|
||||
rows.append(join_cells(row))
|
||||
rows.append(space_row)
|
||||
rgb_data = b''.join(rows)
|
||||
width *= 32
|
||||
height *= len(rows)
|
||||
assert len(rgb_data) == width * height * 3, '{} != {}'.format(len(rgb_data), width * height * 3)
|
||||
display_bitmap(rgb_data, width, height)
|
||||
finally:
|
||||
set_send_sprite_to_gpu(None)
|
||||
|
||||
@@ -201,18 +201,22 @@ def shape_string(text="abcd", family='monospace', size=11.0, dpi=96.0, path=None
|
||||
set_send_sprite_to_gpu(None)
|
||||
|
||||
|
||||
def test_render_string(text='Hello, world!', family='monospace', size=144.0, dpi=96.0):
|
||||
def display_bitmap(rgb_data, width, height):
|
||||
from tempfile import NamedTemporaryFile
|
||||
from kitty.fast_data_types import concat_cells, current_fonts
|
||||
from kitty.icat import detect_support, show
|
||||
if not hasattr(test_render_string, 'detected') and not detect_support():
|
||||
if not hasattr(display_bitmap, 'detected') and not detect_support():
|
||||
raise SystemExit('Your terminal does not support the graphics protocol')
|
||||
test_render_string.detected = True
|
||||
display_bitmap.detected = True
|
||||
with NamedTemporaryFile(delete=False) as f:
|
||||
f.write(rgb_data)
|
||||
show(f.name, width, height, 24)
|
||||
|
||||
|
||||
def test_render_string(text='Hello, world!', family='monospace', size=144.0, dpi=96.0):
|
||||
from kitty.fast_data_types import concat_cells, current_fonts
|
||||
|
||||
cell_width, cell_height, cells = render_string(text, family, size, dpi)
|
||||
rgb_data = concat_cells(cell_width, cell_height, tuple(cells))
|
||||
with NamedTemporaryFile(delete=False) as f:
|
||||
f.write(rgb_data)
|
||||
cf = current_fonts()
|
||||
fonts = [cf['medium'].display_name()]
|
||||
fonts.extend(f.display_name() for f in cf['fallback'])
|
||||
@@ -221,7 +225,7 @@ def test_render_string(text='Hello, world!', family='monospace', size=144.0, dpi
|
||||
print(msg)
|
||||
except UnicodeEncodeError:
|
||||
sys.stdout.buffer.write(msg.encode('utf-8') + b'\n')
|
||||
show(f.name, cell_width * len(cells), cell_height, 24)
|
||||
display_bitmap(rgb_data, cell_width * len(cells), cell_height)
|
||||
print('\n')
|
||||
|
||||
|
||||
|
||||
@@ -130,7 +130,8 @@ set_font_size(Face *self, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt
|
||||
bool
|
||||
set_size_for_face(PyObject *s, unsigned int desired_height, bool force) {
|
||||
Face *self = (Face*)s;
|
||||
FT_UInt w = (FT_UInt)(ceil(global_state.font_sz_in_pts * 64.0)), xdpi = (FT_UInt)global_state.logical_dpi_x, ydpi = (FT_UInt)global_state.logical_dpi_y;
|
||||
FT_F26Dot6 w = (FT_F26Dot6)(ceil(global_state.font_sz_in_pts * 64.0));
|
||||
FT_UInt xdpi = (FT_UInt)global_state.logical_dpi_x, ydpi = (FT_UInt)global_state.logical_dpi_y;
|
||||
if (!force && (self->char_width == w && self->char_height == w && self->xdpi == xdpi && self->ydpi == ydpi)) return true;
|
||||
((Face*)self)->size_in_pts = global_state.font_sz_in_pts;
|
||||
return set_font_size(self, w, w, xdpi, ydpi, desired_height);
|
||||
|
||||
16
kitty/keys.h
generated
16
kitty/keys.h
generated
@@ -569,9 +569,9 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
case 57: // LEFT
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x44";
|
||||
case 58: // DOWN
|
||||
return "\x03\x1b\x5b\x42";
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x42";
|
||||
case 59: // UP
|
||||
return "\x03\x1b\x5b\x41";
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x41";
|
||||
case 60: // PAGE_UP
|
||||
return "\x04\x1b\x5b\x35\x7e";
|
||||
case 61: // PAGE_DOWN
|
||||
@@ -1767,9 +1767,9 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
case 57: // LEFT
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x44";
|
||||
case 58: // DOWN
|
||||
return "\x03\x1b\x5b\x42";
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x42";
|
||||
case 59: // UP
|
||||
return "\x03\x1b\x5b\x41";
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x41";
|
||||
case 60: // PAGE_UP
|
||||
return "\x04\x1b\x5b\x35\x7e";
|
||||
case 61: // PAGE_DOWN
|
||||
@@ -2973,9 +2973,9 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
case 57: // LEFT
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x44";
|
||||
case 58: // DOWN
|
||||
return "\x03\x1b\x4f\x42";
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x42";
|
||||
case 59: // UP
|
||||
return "\x03\x1b\x4f\x41";
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x41";
|
||||
case 60: // PAGE_UP
|
||||
return "\x04\x1b\x5b\x35\x7e";
|
||||
case 61: // PAGE_DOWN
|
||||
@@ -4171,9 +4171,9 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
case 57: // LEFT
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x44";
|
||||
case 58: // DOWN
|
||||
return "\x03\x1b\x4f\x42";
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x42";
|
||||
case 59: // UP
|
||||
return "\x03\x1b\x4f\x41";
|
||||
return "\x06\x1b\x5b\x31\x3b\x32\x41";
|
||||
case 60: // PAGE_UP
|
||||
return "\x04\x1b\x5b\x35\x7e";
|
||||
case 61: // PAGE_DOWN
|
||||
|
||||
@@ -79,6 +79,8 @@ SHIFTED_KEYS = {
|
||||
defines.GLFW_KEY_END: key_as_bytes('kEND'),
|
||||
defines.GLFW_KEY_LEFT: key_as_bytes('kLFT'),
|
||||
defines.GLFW_KEY_RIGHT: key_as_bytes('kRIT'),
|
||||
defines.GLFW_KEY_UP: key_as_bytes('kri'),
|
||||
defines.GLFW_KEY_DOWN: key_as_bytes('kind'),
|
||||
}
|
||||
|
||||
control_codes.update({
|
||||
@@ -225,13 +227,6 @@ def get_shortcut(keymap, mods, key, scancode):
|
||||
return keymap.get((mods & 0b1111, key))
|
||||
|
||||
|
||||
def get_sent_data(send_text_map, key, scancode, mods, window, action):
|
||||
if action in (defines.GLFW_PRESS, defines.GLFW_REPEAT):
|
||||
m = keyboard_mode_name(window.screen)
|
||||
keymap = send_text_map[m]
|
||||
return keymap.get((mods & 0b1111, key))
|
||||
|
||||
|
||||
def generate_key_table():
|
||||
# To run this, use: python3 . -c "from kitty.keys import *; generate_key_table()"
|
||||
import os
|
||||
|
||||
@@ -31,6 +31,12 @@ font_size_delta 2
|
||||
# 100% to reduce line height (but this might cause rendering artifacts).
|
||||
adjust_line_height 0
|
||||
|
||||
# Change the sizes of the lines used for the box drawing unicode characters
|
||||
# These values are in pts. They will be scaled by the monitor DPI to arrive at
|
||||
# a pixel value. There must be four values corresponding to thin, normal, thick,
|
||||
# and very thick lines;
|
||||
box_drawing_scale 0.001, 1, 1.5, 2
|
||||
|
||||
# The foreground color
|
||||
foreground #dddddd
|
||||
|
||||
@@ -298,8 +304,6 @@ map ctrl+shift+f11 toggle_fullscreen
|
||||
# to the start of the line (same as pressing the Home key):
|
||||
# map ctrl+alt+a send_text normal Word\x1b[H
|
||||
# map ctrl+alt+a send_text application Word\x1bOH
|
||||
# There is also a legacy syntax for send_text, which looks like:
|
||||
# send_text all ctrl+alt+a some text
|
||||
|
||||
# Symbol mapping (special font for specified unicode code points). Map the
|
||||
# specified unicode codepoints to a particular font. Useful if you need special
|
||||
|
||||
@@ -268,7 +268,7 @@ linebuf_index(LineBuf* self, index_type top, index_type bottom) {
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
index(LineBuf *self, PyObject *args) {
|
||||
pyw_index(LineBuf *self, PyObject *args) {
|
||||
#define index_doc "index(top, bottom) -> Scroll all lines in the range [top, bottom] by one upwards. After scrolling, bottom will be top."
|
||||
unsigned int top, bottom;
|
||||
if (!PyArg_ParseTuple(args, "II", &top, &bottom)) return NULL;
|
||||
@@ -435,7 +435,7 @@ static PyMethodDef methods[] = {
|
||||
METHOD(set_attribute, METH_VARARGS)
|
||||
METHOD(set_continued, METH_VARARGS)
|
||||
METHOD(dirty_lines, METH_NOARGS)
|
||||
METHOD(index, METH_VARARGS)
|
||||
{"index", (PyCFunction)pyw_index, METH_VARARGS, NULL},
|
||||
METHOD(reverse_index, METH_VARARGS)
|
||||
METHOD(insert_lines, METH_VARARGS)
|
||||
METHOD(delete_lines, METH_VARARGS)
|
||||
|
||||
@@ -161,7 +161,7 @@ url_end_at(Line *self, PyObject *x) {
|
||||
static PyObject*
|
||||
text_at(Line* self, Py_ssize_t xval) {
|
||||
#define text_at_doc "[x] -> Return the text in the specified cell"
|
||||
if (xval >= self->xnum) { PyErr_SetString(PyExc_IndexError, "Column number out of bounds"); return NULL; }
|
||||
if ((unsigned)xval >= self->xnum) { PyErr_SetString(PyExc_IndexError, "Column number out of bounds"); return NULL; }
|
||||
return line_text_at(self->cells[xval].ch, self->cells[xval].cc);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ from .fast_data_types import (
|
||||
glfw_init, glfw_init_hint_string, glfw_swap_interval, glfw_terminate,
|
||||
glfw_window_hint, install_sigchld_handler, set_logical_dpi, set_options
|
||||
)
|
||||
from .fonts.box_drawing import set_scale
|
||||
from .layout import all_layouts
|
||||
from .utils import (
|
||||
color_as_int, detach, end_startup_notification, get_logical_dpi,
|
||||
@@ -170,6 +171,7 @@ def initialize_window(window, opts, debug_gl=False):
|
||||
def run_app(opts, args):
|
||||
set_options(opts)
|
||||
setup_opengl(opts)
|
||||
set_scale(opts.box_drawing_scale)
|
||||
load_cached_values()
|
||||
if 'window-size' in cached_values and opts.remember_window_size:
|
||||
ws = cached_values['window-size']
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
extern PyTypeObject Screen_Type;
|
||||
|
||||
// utils {{{
|
||||
static unsigned long pow10[] = {
|
||||
static uint64_t pow10[] = {
|
||||
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000
|
||||
};
|
||||
|
||||
static inline unsigned long
|
||||
static inline uint64_t
|
||||
utoi(uint32_t *buf, unsigned int sz) {
|
||||
unsigned long ans = 0;
|
||||
uint64_t ans = 0;
|
||||
uint32_t *p = buf;
|
||||
// Ignore leading zeros
|
||||
while(sz > 0) {
|
||||
@@ -27,7 +27,7 @@ utoi(uint32_t *buf, unsigned int sz) {
|
||||
else break;
|
||||
}
|
||||
if (sz < sizeof(pow10)/sizeof(pow10[0])) {
|
||||
for (int i = sz-1, j=0; i >=0; i--, j++) {
|
||||
for (int i = sz-1, j=0; i >= 0; i--, j++) {
|
||||
ans += (p[i] - '0') * pow10[j];
|
||||
}
|
||||
}
|
||||
@@ -1053,7 +1053,7 @@ extern uint32_t *latin1_charset;
|
||||
static inline void
|
||||
_parse_bytes(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject DUMP_UNUSED *dump_callback) {
|
||||
uint32_t prev = screen->utf8_state;
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
for (unsigned int i = 0; i < (unsigned int)len; i++) {
|
||||
if (screen->use_latin1) dispatch_unicode_char(screen, latin1_charset[buf[i]], dump_callback);
|
||||
else {
|
||||
switch (decode_utf8(&screen->utf8_state, &screen->utf8_codepoint, buf[i])) {
|
||||
|
||||
@@ -436,7 +436,8 @@ screen_handle_graphics_command(Screen *self, const GraphicsCommand *cmd, const u
|
||||
if (response != NULL) write_to_child(self, response, strlen(response));
|
||||
if (x != self->cursor->x || y != self->cursor->y) {
|
||||
if (self->cursor->x >= self->columns) { self->cursor->x = 0; self->cursor->y++; }
|
||||
if (self->cursor->y > self->margin_bottom) { screen_scroll(self, self->cursor->y - self->margin_bottom); }
|
||||
if (self->cursor->y > self->margin_bottom) screen_scroll(self, self->cursor->y - self->margin_bottom);
|
||||
screen_ensure_bounds(self, false);
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
@@ -701,7 +702,6 @@ screen_index(Screen *self) {
|
||||
void
|
||||
screen_scroll(Screen *self, unsigned int count) {
|
||||
// Scroll the screen up by count lines, not moving the cursor
|
||||
count = MIN(self->lines, count);
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
while (count > 0) {
|
||||
count--;
|
||||
|
||||
@@ -170,16 +170,10 @@ PYWRAP1(set_options) {
|
||||
OPT(select_by_word_characters)[i] = PyUnicode_READ(PyUnicode_KIND(chars), PyUnicode_DATA(chars), i);
|
||||
}
|
||||
OPT(select_by_word_characters_count) = PyUnicode_GET_LENGTH(chars);
|
||||
Py_DECREF(chars);
|
||||
|
||||
GA(keymap); set_special_keys(ret);
|
||||
Py_DECREF(ret); if (PyErr_Occurred()) return NULL;
|
||||
GA(send_text_map);
|
||||
dict_iter(ret) {
|
||||
set_special_keys(value);
|
||||
}}
|
||||
Py_DECREF(ret); if (PyErr_Occurred()) return NULL;
|
||||
|
||||
Py_DECREF(chars);
|
||||
|
||||
PyObject *al = PyObject_GetAttrString(args, "adjust_line_height");
|
||||
if (PyFloat_Check(al)) {
|
||||
|
||||
@@ -190,6 +190,8 @@ string_capabilities = {
|
||||
'kpp': r'\E[5~',
|
||||
# Scroll backwards (reverse index)
|
||||
'kri': r'\E[1;2A',
|
||||
# scroll forwards (index)
|
||||
'kind': r'\E[1;2B',
|
||||
# Restore cursor
|
||||
'rc': r'\E8',
|
||||
# Reverse video
|
||||
@@ -276,8 +278,6 @@ string_capabilities = {
|
||||
# 'is2': r'\E[!p\E[?3;4l\E[4l\E>',
|
||||
# # Enter/send key
|
||||
# 'kent': r'\EOM',
|
||||
# # scroll forwards
|
||||
# 'kind': r'\E[1;2B',
|
||||
# # reset2
|
||||
# 'rs2': r'\E[!p\E[?3;4l\E[4l\E>',
|
||||
}
|
||||
@@ -350,6 +350,7 @@ termcap_aliases.update({
|
||||
'kN': 'knp',
|
||||
'kP': 'kpp',
|
||||
'kR': 'kri',
|
||||
'kF': 'kind',
|
||||
'rc': 'rc',
|
||||
'mr': 'rev',
|
||||
'sr': 'ri',
|
||||
@@ -400,7 +401,6 @@ termcap_aliases.update({
|
||||
# 'mk': 'invis',
|
||||
# 'is': 'is2',
|
||||
# '@8': 'kent',
|
||||
# 'kF': 'kind',
|
||||
# 'r2': 'rs2',
|
||||
})
|
||||
|
||||
|
||||
Binary file not shown.
@@ -85,6 +85,7 @@ xterm-kitty|KovIdTTY,
|
||||
khlp=,
|
||||
khome=\EOH,
|
||||
kich1=\E[2~,
|
||||
kind=\E[1;2B,
|
||||
kmous=\E[M,
|
||||
knp=\E[6~,
|
||||
kpp=\E[5~,
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user