Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be5185ab1a | ||
|
|
01c289e440 | ||
|
|
db2d14d9ed | ||
|
|
c504b96b60 | ||
|
|
15c4b1961e | ||
|
|
2cc20e4b27 | ||
|
|
0923d6ecee | ||
|
|
defda41861 | ||
|
|
66c51798b8 | ||
|
|
ff966f667c | ||
|
|
96be8dcb2c | ||
|
|
892d3df6eb | ||
|
|
54e79a6901 | ||
|
|
7d0c05e20d | ||
|
|
421ae6d289 | ||
|
|
3af501b715 | ||
|
|
c73d6913da | ||
|
|
f7cb3e3f9e |
@@ -14,6 +14,7 @@ from time import monotonic
|
|||||||
from queue import Queue, Empty
|
from queue import Queue, Empty
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
from .config import MINIMUM_FONT_SIZE
|
||||||
from .constants import (
|
from .constants import (
|
||||||
viewport_size, set_boss, wakeup, cell_size, MODIFIER_KEYS,
|
viewport_size, set_boss, wakeup, cell_size, MODIFIER_KEYS,
|
||||||
main_thread, mouse_button_pressed, mouse_cursor_pos
|
main_thread, mouse_button_pressed, mouse_cursor_pos
|
||||||
@@ -86,6 +87,7 @@ class Boss(Thread):
|
|||||||
self.pending_ui_thread_calls = Queue()
|
self.pending_ui_thread_calls = Queue()
|
||||||
self.write_dispatch_map = {}
|
self.write_dispatch_map = {}
|
||||||
set_boss(self)
|
set_boss(self)
|
||||||
|
self.current_font_size = opts.font_size
|
||||||
cell_size.width, cell_size.height = set_font_family(opts)
|
cell_size.width, cell_size.height = set_font_family(opts)
|
||||||
self.opts, self.args = opts, args
|
self.opts, self.args = opts, args
|
||||||
self.glfw_window = glfw_window
|
self.glfw_window = glfw_window
|
||||||
@@ -228,6 +230,28 @@ class Boss(Thread):
|
|||||||
self.pending_resize = False
|
self.pending_resize = False
|
||||||
glfw_post_empty_event()
|
glfw_post_empty_event()
|
||||||
|
|
||||||
|
def increase_font_size(self):
|
||||||
|
self.change_font_size(min(self.opts.font_size * 5, self.current_font_size + self.opts.font_size_delta))
|
||||||
|
|
||||||
|
def decrease_font_size(self):
|
||||||
|
self.change_font_size(max(MINIMUM_FONT_SIZE, self.current_font_size - self.opts.font_size_delta))
|
||||||
|
|
||||||
|
def restore_font_size(self):
|
||||||
|
self.change_font_size(self.opts.font_size)
|
||||||
|
|
||||||
|
def change_font_size(self, new_size):
|
||||||
|
if new_size == self.current_font_size:
|
||||||
|
return
|
||||||
|
self.current_font_size = new_size
|
||||||
|
cell_size.width, cell_size.height = set_font_family(
|
||||||
|
self.opts, override_font_size=self.current_font_size)
|
||||||
|
self.sprites.do_layout(cell_size.width, cell_size.height)
|
||||||
|
self.queue_action(self.resize_windows_after_font_size_change)
|
||||||
|
|
||||||
|
def resize_windows_after_font_size_change(self):
|
||||||
|
self.tab_manager.resize()
|
||||||
|
glfw_post_empty_event()
|
||||||
|
|
||||||
def tabbar_visibility_changed(self):
|
def tabbar_visibility_changed(self):
|
||||||
self.tab_manager.resize(only_tabs=True)
|
self.tab_manager.resize(only_tabs=True)
|
||||||
glfw_post_empty_event()
|
glfw_post_empty_event()
|
||||||
|
|||||||
@@ -196,12 +196,15 @@ class Selection: # {{{
|
|||||||
if y == b[0]:
|
if y == b[0]:
|
||||||
endx = max(0, min(b[1], endx))
|
endx = max(0, min(b[1], endx))
|
||||||
l = line(y)
|
l = line(y)
|
||||||
|
is_continued = l.is_continued()
|
||||||
if endx - startx >= linebuf.xnum - 1:
|
if endx - startx >= linebuf.xnum - 1:
|
||||||
l = str(l).rstrip(' ')
|
l = str(l).rstrip(' ')
|
||||||
else:
|
else:
|
||||||
l = ''.join(l[x] for x in range(startx, endx + 1))
|
l = ''.join(l[x] for x in range(startx, endx + 1))
|
||||||
|
if not is_continued and startx == 0 and len(lines) > 0:
|
||||||
|
l = '\n' + l
|
||||||
lines.append(l)
|
lines.append(l)
|
||||||
return '\n'.join(lines)
|
return ''.join(lines)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,30 @@ def write(x):
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def set_title(*args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def set_icon(*args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def screen_bell():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def screen_cursor_position(y, x):
|
def screen_cursor_position(y, x):
|
||||||
write(CSI + '%s;%sH' % (y, x))
|
write(CSI + '%s;%sH' % (y, x))
|
||||||
|
|
||||||
|
|
||||||
|
def screen_cursor_forward(amt):
|
||||||
|
write(CSI + '%sC' % amt)
|
||||||
|
|
||||||
|
|
||||||
|
def screen_cursor_back1(amt):
|
||||||
|
write(CSI + '%sD' % amt)
|
||||||
|
|
||||||
|
|
||||||
def screen_designate_charset(which, to):
|
def screen_designate_charset(which, to):
|
||||||
which = '()'[int(which)]
|
which = '()'[int(which)]
|
||||||
to = chr(int(to))
|
to = chr(int(to))
|
||||||
@@ -57,6 +77,10 @@ def screen_erase_in_display(how, private):
|
|||||||
write(CSI + ('?' if private else '') + str(how) + 'J')
|
write(CSI + ('?' if private else '') + str(how) + 'J')
|
||||||
|
|
||||||
|
|
||||||
|
def screen_erase_in_line(how, private):
|
||||||
|
write(CSI + ('?' if private else '') + str(how) + 'K')
|
||||||
|
|
||||||
|
|
||||||
def screen_cursor_up2(count):
|
def screen_cursor_up2(count):
|
||||||
write(CSI + '%dA' % count)
|
write(CSI + '%dA' % count)
|
||||||
|
|
||||||
@@ -65,6 +89,10 @@ def screen_carriage_return():
|
|||||||
write('\r')
|
write('\r')
|
||||||
|
|
||||||
|
|
||||||
|
def screen_linefeed():
|
||||||
|
write('\n')
|
||||||
|
|
||||||
|
|
||||||
def screen_backspace():
|
def screen_backspace():
|
||||||
write('\x08')
|
write('\x08')
|
||||||
|
|
||||||
@@ -77,8 +105,8 @@ def replay(raw):
|
|||||||
for line in raw.splitlines():
|
for line in raw.splitlines():
|
||||||
if line.strip():
|
if line.strip():
|
||||||
cmd, rest = line.partition(' ')[::2]
|
cmd, rest = line.partition(' ')[::2]
|
||||||
if cmd == 'draw':
|
if cmd in {'draw', 'set_title', 'set_icon'}:
|
||||||
draw(rest)
|
globals()[cmd](rest)
|
||||||
else:
|
else:
|
||||||
rest = map(int, rest.split()) if rest else ()
|
rest = map(int, rest.split()) if rest else ()
|
||||||
globals()[cmd](*rest)
|
globals()[cmd](*rest)
|
||||||
|
|||||||
@@ -17,10 +17,11 @@ from .layout import all_layouts
|
|||||||
from .utils import safe_print, to_color
|
from .utils import safe_print, to_color
|
||||||
|
|
||||||
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
|
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
|
||||||
|
MINIMUM_FONT_SIZE = 6
|
||||||
|
|
||||||
|
|
||||||
def to_font_size(x):
|
def to_font_size(x):
|
||||||
return max(6, float(x))
|
return max(MINIMUM_FONT_SIZE, float(x))
|
||||||
|
|
||||||
|
|
||||||
cshapes = {
|
cshapes = {
|
||||||
@@ -153,6 +154,7 @@ type_map = {
|
|||||||
'scrollback_pager': shlex.split,
|
'scrollback_pager': shlex.split,
|
||||||
'scrollback_in_new_tab': to_bool,
|
'scrollback_in_new_tab': to_bool,
|
||||||
'font_size': to_font_size,
|
'font_size': to_font_size,
|
||||||
|
'font_size_delta': float,
|
||||||
'cursor_shape': to_cursor_shape,
|
'cursor_shape': to_cursor_shape,
|
||||||
'cursor_opacity': to_opacity,
|
'cursor_opacity': to_opacity,
|
||||||
'open_url_modifiers': to_open_url_modifiers,
|
'open_url_modifiers': to_open_url_modifiers,
|
||||||
@@ -160,6 +162,7 @@ type_map = {
|
|||||||
'window_border_width': float,
|
'window_border_width': float,
|
||||||
'wheel_scroll_multiplier': float,
|
'wheel_scroll_multiplier': float,
|
||||||
'visual_bell_duration': float,
|
'visual_bell_duration': float,
|
||||||
|
'enable_audio_bell': to_bool,
|
||||||
'click_interval': float,
|
'click_interval': float,
|
||||||
'mouse_hide_wait': float,
|
'mouse_hide_wait': float,
|
||||||
'cursor_blink_interval': float,
|
'cursor_blink_interval': float,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from .fast_data_types import (
|
|||||||
GLFW_KEY_LEFT_SUPER, GLFW_KEY_RIGHT_SUPER)
|
GLFW_KEY_LEFT_SUPER, GLFW_KEY_RIGHT_SUPER)
|
||||||
|
|
||||||
appname = 'kitty'
|
appname = 'kitty'
|
||||||
version = (0, 2, 0)
|
version = (0, 2, 2)
|
||||||
str_version = '.'.join(map(str, version))
|
str_version = '.'.join(map(str, version))
|
||||||
_plat = sys.platform.lower()
|
_plat = sys.platform.lower()
|
||||||
isosx = 'darwin' in _plat
|
isosx = 'darwin' in _plat
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ def install_symbol_map(val, font_size, dpi):
|
|||||||
symbol_map[ch] = family_map[family]
|
symbol_map[ch] = family_map[family]
|
||||||
|
|
||||||
|
|
||||||
def set_font_family(opts, ignore_dpi_failure=False):
|
def set_font_family(opts, override_font_size=None, ignore_dpi_failure=False):
|
||||||
global cell_width, cell_height, baseline, CellTexture, WideCellTexture, underline_thickness, underline_position
|
global cell_width, cell_height, baseline, CellTexture, WideCellTexture, underline_thickness, underline_position
|
||||||
try:
|
try:
|
||||||
dpi = get_logical_dpi()
|
dpi = get_logical_dpi()
|
||||||
@@ -37,11 +37,12 @@ def set_font_family(opts, ignore_dpi_failure=False):
|
|||||||
if ans == 'auto' and (bold or italic):
|
if ans == 'auto' and (bold or italic):
|
||||||
ans = get_family(False, False)
|
ans = get_family(False, False)
|
||||||
return ans
|
return ans
|
||||||
|
font_size = override_font_size or opts.font_size
|
||||||
|
|
||||||
for bold in (False, True):
|
for bold in (False, True):
|
||||||
for italic in (False, True):
|
for italic in (False, True):
|
||||||
main_font[(bold, italic)] = Face(get_family(bold, italic), bold, italic, True, opts.font_size, dpi)
|
main_font[(bold, italic)] = Face(get_family(bold, italic), bold, italic, True, font_size, dpi)
|
||||||
install_symbol_map(opts.symbol_map, opts.font_size, dpi)
|
install_symbol_map(opts.symbol_map, font_size, dpi)
|
||||||
mf = main_font[(False, False)]
|
mf = main_font[(False, False)]
|
||||||
cell_width, cell_height = mf.cell_size()
|
cell_width, cell_height = mf.cell_size()
|
||||||
CellTexture = ctypes.c_ubyte * (cell_width * cell_height)
|
CellTexture = ctypes.c_ubyte * (cell_width * cell_height)
|
||||||
|
|||||||
@@ -71,10 +71,10 @@ def font_units_to_pixels(x, units_per_em, size_in_pts, dpi):
|
|||||||
return ceil_int(x * ((size_in_pts * dpi) / (72 * units_per_em)))
|
return ceil_int(x * ((size_in_pts * dpi) / (72 * units_per_em)))
|
||||||
|
|
||||||
|
|
||||||
def set_font_family(opts):
|
def set_font_family(opts, override_font_size=None):
|
||||||
global current_font_family, current_font_family_name, cff_size, cell_width, cell_height, CharTexture, baseline
|
global current_font_family, current_font_family_name, cff_size, cell_width, cell_height, CharTexture, baseline
|
||||||
global underline_position, underline_thickness
|
global underline_position, underline_thickness
|
||||||
size_in_pts = opts.font_size
|
size_in_pts = override_font_size or opts.font_size
|
||||||
current_font_family = get_font_files(opts)
|
current_font_family = get_font_files(opts)
|
||||||
current_font_family_name = opts.font_family
|
current_font_family_name = opts.font_family
|
||||||
dpi = get_logical_dpi()
|
dpi = get_logical_dpi()
|
||||||
|
|||||||
10
kitty/gl.h
10
kitty/gl.h
@@ -141,10 +141,14 @@ _glewInit(PyObject UNUSED *self) {
|
|||||||
PyErr_Format(PyExc_RuntimeError, "GLEW init failed: %s", glewGetErrorString(err));
|
PyErr_Format(PyExc_RuntimeError, "GLEW init failed: %s", glewGetErrorString(err));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(!GLEW_ARB_texture_storage) {
|
#define ARB_TEST(name) \
|
||||||
PyErr_SetString(PyExc_RuntimeError, "OpenGL is missing the required ARB_texture_storage extension");
|
if (!GLEW_ARB_##name) { \
|
||||||
return NULL;
|
PyErr_Format(PyExc_RuntimeError, "The OpenGL driver on this system is missing the required extension: ARB_%s", #name); \
|
||||||
|
return NULL; \
|
||||||
}
|
}
|
||||||
|
ARB_TEST(texture_storage);
|
||||||
|
ARB_TEST(texture_buffer_object_rgb32);
|
||||||
|
#undef ARB_TEST
|
||||||
#endif
|
#endif
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,12 +50,6 @@ def rkey(name, a, b):
|
|||||||
return bytearray(key_as_bytes(name).replace(a, b))
|
return bytearray(key_as_bytes(name).replace(a, b))
|
||||||
|
|
||||||
|
|
||||||
control_codes[defines.GLFW_KEY_UP] = rkey('cuu1', b'[', b'[1;5')
|
|
||||||
control_codes[defines.GLFW_KEY_DOWN] = rkey('cud1', b'[', b'[1;5')
|
|
||||||
control_codes[defines.GLFW_KEY_LEFT] = rkey('cub1', b'[', b'[1;5')
|
|
||||||
control_codes[defines.GLFW_KEY_RIGHT] = rkey('cuf1', b'[', b'[1;5')
|
|
||||||
control_codes[defines.GLFW_KEY_HOME] = rkey('khome', b'O', b'[1;5')
|
|
||||||
control_codes[defines.GLFW_KEY_END] = rkey('kend', b'O', b'[1;5')
|
|
||||||
control_codes[defines.GLFW_KEY_PAGE_UP] = rkey('kpp', b'~', b';5~')
|
control_codes[defines.GLFW_KEY_PAGE_UP] = rkey('kpp', b'~', b';5~')
|
||||||
control_codes[defines.GLFW_KEY_PAGE_DOWN] = rkey('knp', b'~', b';5~')
|
control_codes[defines.GLFW_KEY_PAGE_DOWN] = rkey('knp', b'~', b';5~')
|
||||||
control_codes[defines.GLFW_KEY_DELETE] = rkey('kdch1', b'~', b';5~')
|
control_codes[defines.GLFW_KEY_DELETE] = rkey('kdch1', b'~', b';5~')
|
||||||
@@ -75,6 +69,10 @@ rmkx_key_map.update({
|
|||||||
defines.GLFW_KEY_HOME: b'\033[H',
|
defines.GLFW_KEY_HOME: b'\033[H',
|
||||||
defines.GLFW_KEY_END: b'\033[F',
|
defines.GLFW_KEY_END: b'\033[F',
|
||||||
})
|
})
|
||||||
|
for sk in 'UP DOWN LEFT RIGHT HOME END'.split():
|
||||||
|
sk = getattr(defines, 'GLFW_KEY_' + sk)
|
||||||
|
control_codes[sk] = rmkx_key_map[sk].replace(b'[', b'[1;5')
|
||||||
|
|
||||||
cursor_key_mode_map = {True: smkx_key_map, False: rmkx_key_map}
|
cursor_key_mode_map = {True: smkx_key_map, False: rmkx_key_map}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ bold_italic_font auto
|
|||||||
# Font size (in pts)
|
# Font size (in pts)
|
||||||
font_size 11.0
|
font_size 11.0
|
||||||
|
|
||||||
|
# The amount the font size is changed by (in pts) when increasing/decreasing
|
||||||
|
# the font size in a running terminal.
|
||||||
|
font_size_delta 2
|
||||||
|
|
||||||
# The foreground color
|
# The foreground color
|
||||||
foreground #dddddd
|
foreground #dddddd
|
||||||
|
|
||||||
@@ -91,6 +95,9 @@ repaint_delay 10
|
|||||||
# seconds. Set to zero to disable.
|
# seconds. Set to zero to disable.
|
||||||
visual_bell_duration 0.0
|
visual_bell_duration 0.0
|
||||||
|
|
||||||
|
# Enable/disable the audio bell. Useful in environments that require silence.
|
||||||
|
enable_audio_bell yes
|
||||||
|
|
||||||
# The modifier keys to press when clicking with the mouse on URLs to open the URL
|
# The modifier keys to press when clicking with the mouse on URLs to open the URL
|
||||||
open_url_modifiers ctrl+shift
|
open_url_modifiers ctrl+shift
|
||||||
|
|
||||||
@@ -212,6 +219,10 @@ map ctrl+shift+l next_layout
|
|||||||
map ctrl+shift+. move_tab_forward
|
map ctrl+shift+. move_tab_forward
|
||||||
map ctrl+shift+, move_tab_backward
|
map ctrl+shift+, move_tab_backward
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
map ctrl+shift+equal increase_font_size
|
||||||
|
map ctrl+shift+minus decrease_font_size
|
||||||
|
map ctrl+shift+backspace restore_font_size
|
||||||
|
|
||||||
# Symbol mapping (special font for specified unicode code points). Map the
|
# Symbol mapping (special font for specified unicode code points). Map the
|
||||||
# specified unicode codepoints to a particular font. Useful if you need special
|
# specified unicode codepoints to a particular font. Useful if you need special
|
||||||
|
|||||||
18
kitty/line.c
18
kitty/line.c
@@ -200,6 +200,14 @@ as_ansi(Line* self) {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
is_continued(Line* self) {
|
||||||
|
#define is_continued_doc "Return the line's continued flag"
|
||||||
|
PyObject *ans = self->continued ? Py_True : Py_False;
|
||||||
|
Py_INCREF(ans);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
__repr__(Line* self) {
|
__repr__(Line* self) {
|
||||||
PyObject *s = as_unicode(self);
|
PyObject *s = as_unicode(self);
|
||||||
@@ -305,7 +313,8 @@ cursor_from(Line* self, PyObject *args) {
|
|||||||
return (PyObject*)ans;
|
return (PyObject*)ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
void line_clear_text(Line *self, unsigned int at, unsigned int num, int ch) {
|
void
|
||||||
|
line_clear_text(Line *self, unsigned int at, unsigned int num, int ch) {
|
||||||
const char_type repl = ((char_type)ch & CHAR_MASK) | (1 << ATTRS_SHIFT);
|
const char_type repl = ((char_type)ch & CHAR_MASK) | (1 << ATTRS_SHIFT);
|
||||||
for (index_type i = at; i < MIN(self->xnum, at + num); i++) {
|
for (index_type i = at; i < MIN(self->xnum, at + num); i++) {
|
||||||
self->chars[i] = (self->chars[i] & ATTRS_MASK_WITHOUT_WIDTH) | repl;
|
self->chars[i] = (self->chars[i] & ATTRS_MASK_WITHOUT_WIDTH) | repl;
|
||||||
@@ -323,7 +332,8 @@ clear_text(Line* self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char) {
|
void
|
||||||
|
line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char) {
|
||||||
char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
|
char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
|
||||||
color_type col = (cursor->fg & COL_MASK) | ((color_type)(cursor->bg & COL_MASK) << COL_SHIFT);
|
color_type col = (cursor->fg & COL_MASK) | ((color_type)(cursor->bg & COL_MASK) << COL_SHIFT);
|
||||||
decoration_type dfg = cursor->decoration_fg & COL_MASK;
|
decoration_type dfg = cursor->decoration_fg & COL_MASK;
|
||||||
@@ -390,7 +400,8 @@ left_shift(Line *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor) {
|
void
|
||||||
|
line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor) {
|
||||||
char_type attrs;
|
char_type attrs;
|
||||||
if (cursor == NULL) {
|
if (cursor == NULL) {
|
||||||
attrs = (((self->chars[at] >> ATTRS_SHIFT) & ~3) | (width & 3)) << ATTRS_SHIFT;
|
attrs = (((self->chars[at] >> ATTRS_SHIFT) & ~3) | (width & 3)) << ATTRS_SHIFT;
|
||||||
@@ -470,6 +481,7 @@ static PyMethodDef methods[] = {
|
|||||||
METHOD(set_attribute, METH_VARARGS)
|
METHOD(set_attribute, METH_VARARGS)
|
||||||
METHOD(as_base_text, METH_NOARGS)
|
METHOD(as_base_text, METH_NOARGS)
|
||||||
METHOD(as_ansi, METH_NOARGS)
|
METHOD(as_ansi, METH_NOARGS)
|
||||||
|
METHOD(is_continued, METH_NOARGS)
|
||||||
METHOD(width, METH_O)
|
METHOD(width, METH_O)
|
||||||
METHOD(basic_cell_data, METH_O)
|
METHOD(basic_cell_data, METH_O)
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,19 @@ def option_parser():
|
|||||||
default=None,
|
default=None,
|
||||||
help=_('Replay previously dumped commands')
|
help=_('Replay previously dumped commands')
|
||||||
)
|
)
|
||||||
|
a(
|
||||||
|
'--dump-bytes',
|
||||||
|
help=_('Path to file in which to store the raw bytes received from the'
|
||||||
|
' child process. Useful for debugging.')
|
||||||
|
)
|
||||||
|
a(
|
||||||
|
'--debug-gl',
|
||||||
|
action='store_true',
|
||||||
|
default=False,
|
||||||
|
help=_('Debug OpenGL commands. This will cause all OpenGL calls'
|
||||||
|
' to check for errors instead of ignoring them. Useful'
|
||||||
|
' when debugging rendering problems.')
|
||||||
|
)
|
||||||
a(
|
a(
|
||||||
'--window-layout',
|
'--window-layout',
|
||||||
default=None,
|
default=None,
|
||||||
@@ -226,7 +239,7 @@ def main():
|
|||||||
opts = load_config(*config, overrides=overrides)
|
opts = load_config(*config, overrides=overrides)
|
||||||
change_wcwidth(not opts.use_system_wcwidth)
|
change_wcwidth(not opts.use_system_wcwidth)
|
||||||
glfw_set_error_callback(on_glfw_error)
|
glfw_set_error_callback(on_glfw_error)
|
||||||
enable_automatic_opengl_error_checking(False)
|
enable_automatic_opengl_error_checking(args.debug_gl)
|
||||||
if not glfw_init():
|
if not glfw_init():
|
||||||
raise SystemExit('GLFW initialization failed')
|
raise SystemExit('GLFW initialization failed')
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -519,16 +519,16 @@ accumulate_osc(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback)
|
|||||||
switch(ch) {
|
switch(ch) {
|
||||||
case ST:
|
case ST:
|
||||||
return true;
|
return true;
|
||||||
case ESC_ST:
|
|
||||||
if (screen->parser_buf_pos > 0 && screen->parser_buf[screen->parser_buf_pos - 1] == ESC) {
|
|
||||||
screen->parser_buf_pos--;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case BEL:
|
case BEL:
|
||||||
return true;
|
return true;
|
||||||
case NUL:
|
case NUL:
|
||||||
case DEL:
|
case DEL:
|
||||||
break;
|
break;
|
||||||
|
case ESC_ST:
|
||||||
|
if (screen->parser_buf_pos > 0 && screen->parser_buf[screen->parser_buf_pos - 1] == ESC) {
|
||||||
|
screen->parser_buf_pos--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (screen->parser_buf_pos >= PARSER_BUF_SZ - 1) {
|
if (screen->parser_buf_pos >= PARSER_BUF_SZ - 1) {
|
||||||
REPORT_ERROR("OSC sequence too long, truncating.");
|
REPORT_ERROR("OSC sequence too long, truncating.");
|
||||||
@@ -753,6 +753,11 @@ FNAME(read_bytes)(PyObject UNUSED *self, PyObject *args) {
|
|||||||
/* PyObject_Print(Py_BuildValue("y#", screen->read_buf, len), stderr, 0); */
|
/* PyObject_Print(Py_BuildValue("y#", screen->read_buf, len), stderr, 0); */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef DUMP_COMMANDS
|
||||||
|
if (len > 0) {
|
||||||
|
Py_XDECREF(PyObject_CallFunction(dump_callback, "sy#", "bytes", screen->read_buf, len)); PyErr_Clear();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
_parse_bytes(screen, screen->read_buf, len, dump_callback);
|
_parse_bytes(screen, screen->read_buf, len, dump_callback);
|
||||||
if(len > 0) { Py_RETURN_TRUE; }
|
if(len > 0) { Py_RETURN_TRUE; }
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ class Sprites:
|
|||||||
return glGenBuffers(1)
|
return glGenBuffers(1)
|
||||||
|
|
||||||
def set_sprite_map(self, buf_id, data, usage=GL_STREAM_DRAW):
|
def set_sprite_map(self, buf_id, data, usage=GL_STREAM_DRAW):
|
||||||
|
self.bind_sprite_map(buf_id)
|
||||||
glNamedBufferData(buf_id, sizeof(data), addressof(data), usage)
|
glNamedBufferData(buf_id, sizeof(data), addressof(data), usage)
|
||||||
|
|
||||||
def bind_sprite_map(self, buf_id):
|
def bind_sprite_map(self, buf_id):
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ class Window:
|
|||||||
self.child_fd = child.child_fd
|
self.child_fd = child.child_fd
|
||||||
self.start_visual_bell_at = None
|
self.start_visual_bell_at = None
|
||||||
self.screen = Screen(self, 24, 80, opts.scrollback_lines)
|
self.screen = Screen(self, 24, 80, opts.scrollback_lines)
|
||||||
self.read_bytes = partial(read_bytes_dump, self.dump_commands) if args.dump_commands else read_bytes
|
self.read_bytes = partial(read_bytes_dump, self.dump_commands) if args.dump_commands or args.dump_bytes else read_bytes
|
||||||
|
if args.dump_bytes:
|
||||||
|
self.dump_bytes_to = open(args.dump_bytes, 'ab')
|
||||||
self.draw_dump_buf = []
|
self.draw_dump_buf = []
|
||||||
self.write_buf = memoryview(b'')
|
self.write_buf = memoryview(b'')
|
||||||
self.char_grid = CharGrid(self.screen, opts)
|
self.char_grid = CharGrid(self.screen, opts)
|
||||||
@@ -108,11 +110,12 @@ class Window:
|
|||||||
wakeup()
|
wakeup()
|
||||||
|
|
||||||
def bell(self):
|
def bell(self):
|
||||||
try:
|
if self.opts.enable_audio_bell:
|
||||||
with open('/dev/tty', 'wb') as f:
|
try:
|
||||||
f.write(b'\007')
|
with open('/dev/tty', 'wb') as f:
|
||||||
except EnvironmentError:
|
f.write(b'\007')
|
||||||
pass # failure to beep is not critical
|
except EnvironmentError:
|
||||||
|
pass # failure to beep is not critical
|
||||||
if self.opts.visual_bell_duration > 0:
|
if self.opts.visual_bell_duration > 0:
|
||||||
self.start_visual_bell_at = monotonic()
|
self.start_visual_bell_at = monotonic()
|
||||||
glfw_post_empty_event()
|
glfw_post_empty_event()
|
||||||
@@ -346,6 +349,9 @@ class Window:
|
|||||||
self.draw_dump_buf = []
|
self.draw_dump_buf = []
|
||||||
else:
|
else:
|
||||||
self.draw_dump_buf.append(a[1])
|
self.draw_dump_buf.append(a[1])
|
||||||
|
elif a[0] == 'bytes':
|
||||||
|
self.dump_bytes_to.write(a[1])
|
||||||
|
self.dump_bytes_to.flush()
|
||||||
else:
|
else:
|
||||||
if self.draw_dump_buf:
|
if self.draw_dump_buf:
|
||||||
safe_print('draw', ''.join(self.draw_dump_buf))
|
safe_print('draw', ''.join(self.draw_dump_buf))
|
||||||
|
|||||||
@@ -156,9 +156,9 @@ class TestParser(BaseTest):
|
|||||||
s = self.create_screen()
|
s = self.create_screen()
|
||||||
pb = partial(self.parse_bytes_dump, s)
|
pb = partial(self.parse_bytes_dump, s)
|
||||||
c = s.callbacks
|
c = s.callbacks
|
||||||
pb('a\033]2;xyz\x9cbcde', 'a', ('set_title', 'xyz'), 'bcde')
|
pb('a\033]2;x\\ryz\x9cbcde', 'a', ('set_title', 'x\\ryz'), 'bcde')
|
||||||
self.ae(str(s.line(0)), 'abcde')
|
self.ae(str(s.line(0)), 'abcde')
|
||||||
self.ae(c.titlebuf, 'xyz')
|
self.ae(c.titlebuf, 'x\\ryz')
|
||||||
c.clear()
|
c.clear()
|
||||||
pb('\033]\x07', ('set_title', ''), ('set_icon', ''))
|
pb('\033]\x07', ('set_title', ''), ('set_icon', ''))
|
||||||
self.ae(c.titlebuf, ''), self.ae(c.iconbuf, '')
|
self.ae(c.titlebuf, ''), self.ae(c.iconbuf, '')
|
||||||
@@ -181,4 +181,4 @@ class TestParser(BaseTest):
|
|||||||
pb = partial(self.parse_bytes_dump, s)
|
pb = partial(self.parse_bytes_dump, s)
|
||||||
for prefix in '\033_', '\033^', '\u009e', '\u009f':
|
for prefix in '\033_', '\033^', '\u009e', '\u009f':
|
||||||
for suffix in '\u009c', '\033\\':
|
for suffix in '\u009c', '\033\\':
|
||||||
pb('a{}+++{}bcde'.format(prefix, suffix), 'abcde')
|
pb('a{}+\\++{}bcde'.format(prefix, suffix), 'abcde')
|
||||||
|
|||||||
@@ -7,6 +7,15 @@ These are typically in the form of new or re-purposed escape codes. While these
|
|||||||
extensions are currently kitty specific, it would be nice to get some of them
|
extensions are currently kitty specific, it would be nice to get some of them
|
||||||
adopted more broadly, to push the state of terminal emulators forward.
|
adopted more broadly, to push the state of terminal emulators forward.
|
||||||
|
|
||||||
|
The goal of these extensions is to be as small an unobtrusive as possible,
|
||||||
|
while filling in some gaps in the existing xterm protocol. In particular, one
|
||||||
|
of the goals of this specification is explicitly not to "re-imagine" the tty.
|
||||||
|
The tty should remain what it is -- a device for efficiently processing text
|
||||||
|
received as a simple byte stream. Another objective is to only move the minimum
|
||||||
|
possible amount of extra functionality into the terminal program itself. This
|
||||||
|
is to make it as easy to implement these protocol extensions as possible,
|
||||||
|
thereby hopefully encouraging their widespread adoption.
|
||||||
|
|
||||||
If you wish to discuss these extensions, propose additions/changes to them
|
If you wish to discuss these extensions, propose additions/changes to them
|
||||||
please do so by opening issues in the github bug tracker.
|
please do so by opening issues in the github bug tracker.
|
||||||
|
|
||||||
@@ -19,9 +28,6 @@ in terminal editors such as vim and emacs to display red, wavy underlines under
|
|||||||
mis-spelled words and/or syntax errors. This is done by re-purposing some SGR escape codes
|
mis-spelled words and/or syntax errors. This is done by re-purposing some SGR escape codes
|
||||||
that are not used in modern terminals (https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes)
|
that are not used in modern terminals (https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes)
|
||||||
|
|
||||||
Setting the width and/or height to zero means that no drawing is done and the
|
|
||||||
cursor position remains unchanged.
|
|
||||||
|
|
||||||
To change the underline style from straight line to curl (this used to be the
|
To change the underline style from straight line to curl (this used to be the
|
||||||
code for rapid blinking text, only previous use I know of was in MS-DOS ANSI.sys):
|
code for rapid blinking text, only previous use I know of was in MS-DOS ANSI.sys):
|
||||||
|
|
||||||
|
|||||||
18
setup.py
18
setup.py
@@ -88,8 +88,9 @@ def get_python_flags(cflags):
|
|||||||
return libs
|
return libs
|
||||||
|
|
||||||
|
|
||||||
def init_env(debug=False, asan=False):
|
def init_env(debug=False, asan=False, native_optimizations=True):
|
||||||
global cflags, ldflags, cc, ldpaths
|
global cflags, ldflags, cc, ldpaths
|
||||||
|
native_optimizations = native_optimizations and not asan and not debug
|
||||||
ccver = cc_version()
|
ccver = cc_version()
|
||||||
stack_protector = '-fstack-protector'
|
stack_protector = '-fstack-protector'
|
||||||
if ccver >= (4, 9):
|
if ccver >= (4, 9):
|
||||||
@@ -106,8 +107,11 @@ def init_env(debug=False, asan=False):
|
|||||||
cflags = os.environ.get(
|
cflags = os.environ.get(
|
||||||
'OVERRIDE_CFLAGS', (
|
'OVERRIDE_CFLAGS', (
|
||||||
'-Wextra -Wno-missing-field-initializers -Wall -std=c99 -D_XOPEN_SOURCE=700'
|
'-Wextra -Wno-missing-field-initializers -Wall -std=c99 -D_XOPEN_SOURCE=700'
|
||||||
' -pedantic-errors -Werror {} -DNDEBUG -fwrapv {} {} -pipe'
|
' -pedantic-errors -Werror {} -DNDEBUG -fwrapv {} {} -pipe {}'
|
||||||
).format(optimize, stack_protector, missing_braces)
|
).format(
|
||||||
|
optimize, stack_protector, missing_braces, '-march=native'
|
||||||
|
if native_optimizations else ''
|
||||||
|
)
|
||||||
)
|
)
|
||||||
cflags = shlex.split(cflags
|
cflags = shlex.split(cflags
|
||||||
) + shlex.split(sysconfig.get_config_var('CCSHARED'))
|
) + shlex.split(sysconfig.get_config_var('CCSHARED'))
|
||||||
@@ -263,8 +267,8 @@ def find_c_files():
|
|||||||
return tuple(ans), tuple(headers)
|
return tuple(ans), tuple(headers)
|
||||||
|
|
||||||
|
|
||||||
def build(args):
|
def build(args, native_optimizations=True):
|
||||||
init_env(args.debug, args.asan)
|
init_env(args.debug, args.asan, native_optimizations)
|
||||||
compile_c_extension(
|
compile_c_extension(
|
||||||
'kitty/fast_data_types', args.incremental, *find_c_files()
|
'kitty/fast_data_types', args.incremental, *find_c_files()
|
||||||
)
|
)
|
||||||
@@ -361,10 +365,10 @@ def main():
|
|||||||
sys.executable, sys.executable, os.path.join(base, 'test.py')
|
sys.executable, sys.executable, os.path.join(base, 'test.py')
|
||||||
)
|
)
|
||||||
elif args.action == 'linux-package':
|
elif args.action == 'linux-package':
|
||||||
build(args)
|
build(args, native_optimizations=False)
|
||||||
package(args)
|
package(args)
|
||||||
elif args.action == 'osx-bundle':
|
elif args.action == 'osx-bundle':
|
||||||
build(args)
|
build(args, native_optimizations=False)
|
||||||
package(args, for_bundle=True)
|
package(args, for_bundle=True)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user