Compare commits

...

18 Commits

Author SHA1 Message Date
Kovid Goyal
be5185ab1a version 0.2.2 2017-04-05 09:12:10 +05:30
Kovid Goyal
01c289e440 Add ST test to OTH tests as well 2017-04-05 09:09:41 +05:30
Kovid Goyal
db2d14d9ed Fix backslashes in OSC codes not being parsed correctly
Fixes #61
2017-04-05 09:07:55 +05:30
Kovid Goyal
c504b96b60 Add a --dump-bytes option, useful for reproducing problems from users computers 2017-04-05 00:13:31 +05:30
Kovid Goyal
15c4b1961e Add a few missing commands to replay 2017-04-04 23:51:20 +05:30
Kovid Goyal
2cc20e4b27 Allow changing font size in a running terminal using keyboard shortcuts.
Fixes #57
2017-03-31 10:00:56 +05:30
Kovid Goyal
0923d6ecee version 0.2.1 2017-03-15 16:31:28 +05:30
Kovid Goyal
defda41861 Use rmkx codes as basis for control+special key codes 2017-03-15 16:27:17 +05:30
Kovid Goyal
66c51798b8 Fix a regression that broke Ctrl+Left and Ctrl+Down
Fixes #56
2017-03-15 16:16:27 +05:30
Kovid Goyal
ff966f667c Fix newlines being inserted at wrapping boundaries when copying. Fixes #55 2017-03-10 10:02:22 +05:30
Kovid Goyal
96be8dcb2c Remove spurious sentence 2017-03-09 09:14:17 +05:30
Kovid Goyal
892d3df6eb DRYer 2017-02-24 15:56:04 +05:30
Kovid Goyal
54e79a6901 Add a test for ARB_texture_buffer_object_rgb32
There are apparently some drivers on linux that are missing it,
see #54
2017-02-24 15:27:41 +05:30
Kovid Goyal
7d0c05e20d Add a command line option to debug OpenGL calls 2017-02-24 14:38:30 +05:30
Kovid Goyal
421ae6d289 Ensure texture buffer is bound before uploading to it 2017-02-24 14:35:02 +05:30
Kovid Goyal
3af501b715 Build with -march=native by default 2017-02-21 16:35:25 +05:30
Kovid Goyal
c73d6913da Some meta goals for the protocol extensions 2017-02-17 22:06:11 +05:30
Kovid Goyal
f7cb3e3f9e Option to disable audio bell 2017-02-14 08:10:00 +05:30
18 changed files with 166 additions and 47 deletions

View File

@@ -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()

View File

@@ -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)
# }}} # }}}

View File

@@ -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)

View File

@@ -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,

View File

@@ -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

View File

@@ -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)

View File

@@ -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()

View File

@@ -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;
} }

View File

@@ -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}

View File

@@ -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

View File

@@ -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)

View File

@@ -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:

View File

@@ -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;

View File

@@ -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):

View File

@@ -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))

View File

@@ -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')

View File

@@ -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):

View File

@@ -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)