mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-21 16:05:02 +02:00
Clean up the mode handling code
This commit is contained in:
@@ -224,7 +224,9 @@ PyTypeObject ChangeTracker_Type;
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mBRACKETED_PASTE, mFOCUS_TRACKING;
|
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM,
|
||||||
|
mBRACKETED_PASTE, mFOCUS_TRACKING, mMOUSE_BUTTON_TRACKING,
|
||||||
|
mMOUSE_MOTION_TRACKING, mMOUSE_SGR_MODE;
|
||||||
} ScreenModes;
|
} ScreenModes;
|
||||||
PyTypeObject ScreenModes_Type;
|
PyTypeObject ScreenModes_Type;
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,13 @@
|
|||||||
|
|
||||||
// Private modes.
|
// Private modes.
|
||||||
|
|
||||||
// *Text Cursor Enable Mode*: determines if the text cursor is visible.
|
// Arrow keys send application sequences or cursor movement commands
|
||||||
#define DECTCEM (25 << 5)
|
#define DECCKM (1 << 5)
|
||||||
|
|
||||||
|
// *Column Mode*: selects the number of columns per line (80 or 132)
|
||||||
|
// on the screen.
|
||||||
|
#define DECCOLM (3 << 5)
|
||||||
|
|
||||||
|
|
||||||
// *Screen Mode*: toggles screen-wide reverse-video mode.
|
// *Screen Mode*: toggles screen-wide reverse-video mode.
|
||||||
#define DECSCNM (5 << 5)
|
#define DECSCNM (5 << 5)
|
||||||
@@ -39,23 +44,23 @@
|
|||||||
// when the cursor is at the right margin.
|
// when the cursor is at the right margin.
|
||||||
#define DECAWM (7 << 5)
|
#define DECAWM (7 << 5)
|
||||||
|
|
||||||
// *Column Mode*: selects the number of columns per line (80 or 132)
|
// Toggle cursor blinking
|
||||||
// on the screen.
|
#define CONTROL_CURSOR_BLINK (12 << 5)
|
||||||
#define DECCOLM (3 << 5)
|
|
||||||
|
// *Text Cursor Enable Mode*: determines if the text cursor is visible.
|
||||||
|
#define DECTCEM (25 << 5)
|
||||||
|
|
||||||
|
// Xterm mouse protocol
|
||||||
|
#define MOUSE_BUTTON_TRACKING (1000 << 5)
|
||||||
|
#define MOUSE_MOTION_TRACKING (1002 << 5)
|
||||||
|
#define FOCUS_TRACKING (1004 << 5)
|
||||||
|
#define MOUSE_SGR_MODE (1006 << 6)
|
||||||
|
|
||||||
|
// Alternate screen buffer
|
||||||
|
#define ALTERNATE_SCREEN (1049 << 5)
|
||||||
|
|
||||||
// Bracketed paste mode
|
// Bracketed paste mode
|
||||||
// http://cirw.in/blog/bracketed-paste
|
// http://cirw.in/blog/bracketed-paste
|
||||||
#define BRACKETED_PASTE (2004 << 5)
|
#define BRACKETED_PASTE (2004 << 5)
|
||||||
#define BRACKETED_PASTE_START "\033[200~"
|
#define BRACKETED_PASTE_START "\033[200~"
|
||||||
#define BRACKETED_PASTE_END "\033[201~"
|
#define BRACKETED_PASTE_END "\033[201~"
|
||||||
|
|
||||||
// Alternate screen buffer
|
|
||||||
#define ALTERNATE_SCREEN (1049 << 5)
|
|
||||||
|
|
||||||
// Xterm mouse protocol
|
|
||||||
#define SEND_MOUSE_ON_PRESS_AND_RELEASE (1000 << 5)
|
|
||||||
#define HILITE_MOUSE_TRACKING (1001 << 5)
|
|
||||||
#define CELL_MOTION_MOUSE_TRACKING (1002 << 5)
|
|
||||||
#define FOCUS_TRACKING (1004 << 5)
|
|
||||||
#define SGR_MOUSE_MODE (1006 << 6)
|
|
||||||
|
|
||||||
|
|||||||
154
kitty/screen.c
154
kitty/screen.c
@@ -294,105 +294,78 @@ void screen_toggle_screen_buffer(Screen *self) {
|
|||||||
void screen_normal_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
|
void screen_normal_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
|
||||||
void screen_alternate_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
|
void screen_alternate_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
|
||||||
|
|
||||||
static inline void set_mode_from_const(Screen *self, unsigned int mode, bool val) {
|
static inline void
|
||||||
|
set_mode_from_const(Screen *self, unsigned int mode, bool val) {
|
||||||
|
#define SIMPLE_MODE(name) \
|
||||||
|
case name: \
|
||||||
|
self->modes.m##name = val; break;
|
||||||
|
|
||||||
|
bool private;
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
case LNM:
|
SIMPLE_MODE(LNM)
|
||||||
self->modes.mLNM = val; break;
|
SIMPLE_MODE(IRM)
|
||||||
case IRM:
|
SIMPLE_MODE(BRACKETED_PASTE)
|
||||||
self->modes.mIRM = val; break;
|
SIMPLE_MODE(MOUSE_BUTTON_TRACKING)
|
||||||
|
SIMPLE_MODE(MOUSE_MOTION_TRACKING)
|
||||||
|
SIMPLE_MODE(MOUSE_SGR_MODE)
|
||||||
|
SIMPLE_MODE(FOCUS_TRACKING)
|
||||||
|
|
||||||
|
case DECCKM:
|
||||||
|
break; // we ignore this mode
|
||||||
case DECTCEM:
|
case DECTCEM:
|
||||||
self->modes.mDECTCEM = val; break;
|
self->modes.mDECTCEM = val;
|
||||||
|
if ((val && self->cursor->hidden) || (!val && !self->cursor->hidden)) {
|
||||||
|
self->cursor->hidden = !val;
|
||||||
|
tracker_cursor_changed(self->change_tracker);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case DECSCNM:
|
case DECSCNM:
|
||||||
self->modes.mDECSCNM = val; break;
|
// Mark all displayed characters as reverse.
|
||||||
|
self->modes.mDECSCNM = val;
|
||||||
|
linebuf_set_attribute(self->linebuf, REVERSE_SHIFT, 0);
|
||||||
|
tracker_update_screen(self->change_tracker);
|
||||||
|
self->cursor->reverse = val;
|
||||||
|
tracker_cursor_changed(self->change_tracker);
|
||||||
|
break;
|
||||||
case DECOM:
|
case DECOM:
|
||||||
self->modes.mDECOM = val; break;
|
self->modes.mDECOM = val;
|
||||||
|
// According to `vttest`, DECOM should also home the cursor, see
|
||||||
|
// vttest/main.c:303.
|
||||||
|
screen_cursor_position(self, 1, 1);
|
||||||
|
break;
|
||||||
case DECAWM:
|
case DECAWM:
|
||||||
self->modes.mDECAWM = val; break;
|
self->modes.mDECAWM = val; break;
|
||||||
case DECCOLM:
|
case DECCOLM:
|
||||||
self->modes.mDECCOLM = val; break;
|
// When DECCOLM mode is set, the screen is erased and the cursor
|
||||||
case BRACKETED_PASTE:
|
// moves to the home position.
|
||||||
self->modes.mBRACKETED_PASTE = val; break;
|
self->modes.mDECCOLM = val;
|
||||||
case FOCUS_TRACKING:
|
screen_erase_in_display(self, 2, false);
|
||||||
self->modes.mFOCUS_TRACKING = val; break;
|
screen_cursor_position(self, 1, 1);
|
||||||
|
break;
|
||||||
|
case CONTROL_CURSOR_BLINK:
|
||||||
|
self->cursor->blink = val;
|
||||||
|
tracker_cursor_changed(self->change_tracker);
|
||||||
|
break;
|
||||||
|
case ALTERNATE_SCREEN:
|
||||||
|
if (val && self->linebuf == self->main_linebuf) screen_toggle_screen_buffer(self);
|
||||||
|
else if (!val && self->linebuf != self->main_linebuf) screen_toggle_screen_buffer(self);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
private = mode >= 1 << 5;
|
||||||
|
if (private) mode >>= 5;
|
||||||
|
fprintf(stderr, "%s %s %u %s\n", ERROR_PREFIX, "Unsupported screen mode: ", mode, private ? "(private)" : "");
|
||||||
}
|
}
|
||||||
|
#undef SIMPLE_MODE
|
||||||
}
|
}
|
||||||
|
|
||||||
void screen_set_mode(Screen *self, unsigned int mode) {
|
void screen_set_mode(Screen *self, unsigned int mode) {
|
||||||
if (mode == DECCOLM) {
|
|
||||||
// When DECCOLM mode is set, the screen is erased and the cursor
|
|
||||||
// moves to the home position.
|
|
||||||
screen_erase_in_display(self, 2, false);
|
|
||||||
screen_cursor_position(self, 1, 1);
|
|
||||||
}
|
|
||||||
// According to `vttest`, DECOM should also home the cursor, see
|
|
||||||
// vttest/main.c:303.
|
|
||||||
if (mode == DECOM) screen_cursor_position(self, 1, 1);
|
|
||||||
|
|
||||||
if (mode == DECSCNM) {
|
|
||||||
// Mark all displayed characters as reverse.
|
|
||||||
linebuf_set_attribute(self->linebuf, REVERSE_SHIFT, 1);
|
|
||||||
tracker_update_screen(self->change_tracker);
|
|
||||||
self->cursor->reverse = true;
|
|
||||||
tracker_cursor_changed(self->change_tracker);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == DECTCEM && self->cursor->hidden) {
|
|
||||||
self->cursor->hidden = false;
|
|
||||||
tracker_cursor_changed(self->change_tracker);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == ALTERNATE_SCREEN && self->linebuf == self->main_linebuf) {
|
|
||||||
screen_toggle_screen_buffer(self);
|
|
||||||
}
|
|
||||||
set_mode_from_const(self, mode, true);
|
set_mode_from_const(self, mode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
|
||||||
in_bracketed_paste_mode(Screen *self) {
|
|
||||||
#define in_bracketed_paste_mode_doc ""
|
|
||||||
PyObject *ans = self->modes.mBRACKETED_PASTE ? Py_True : Py_False;
|
|
||||||
Py_INCREF(ans);
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject*
|
|
||||||
focus_tracking_enabled(Screen *self) {
|
|
||||||
#define focus_tracking_enabled_doc ""
|
|
||||||
PyObject *ans = self->modes.mFOCUS_TRACKING ? Py_True : Py_False;
|
|
||||||
Py_INCREF(ans);
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
|
|
||||||
void screen_reset_mode(Screen *self, unsigned int mode) {
|
void screen_reset_mode(Screen *self, unsigned int mode) {
|
||||||
if (mode == DECCOLM) {
|
|
||||||
// When DECCOLM mode is set, the screen is erased and the cursor
|
|
||||||
// moves to the home position.
|
|
||||||
screen_erase_in_display(self, 2, false);
|
|
||||||
screen_cursor_position(self, 1, 1);
|
|
||||||
}
|
|
||||||
// According to `vttest`, DECOM should also home the cursor, see
|
|
||||||
// vttest/main.c:303.
|
|
||||||
if (mode == DECOM) screen_cursor_position(self, 1, 1);
|
|
||||||
|
|
||||||
if (mode == DECSCNM) {
|
|
||||||
// Mark all displayed characters as reverse.
|
|
||||||
linebuf_set_attribute(self->linebuf, REVERSE_SHIFT, 0);
|
|
||||||
tracker_update_screen(self->change_tracker);
|
|
||||||
self->cursor->reverse = false;
|
|
||||||
tracker_cursor_changed(self->change_tracker);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == DECTCEM && !self->cursor->hidden) {
|
|
||||||
self->cursor->hidden = true;
|
|
||||||
tracker_cursor_changed(self->change_tracker);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == ALTERNATE_SCREEN && self->linebuf != self->main_linebuf) {
|
|
||||||
screen_toggle_screen_buffer(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_mode_from_const(self, mode, false);
|
set_mode_from_const(self, mode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// Cursor {{{
|
// Cursor {{{
|
||||||
@@ -934,6 +907,16 @@ erase_in_display(Screen *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MODE_GETTER(name, uname) \
|
||||||
|
static PyObject* name(Screen *self) { PyObject *ans = self->modes.m##uname ? Py_True : Py_False; Py_INCREF(ans); return ans; }
|
||||||
|
|
||||||
|
MODE_GETTER(in_bracketed_paste, BRACKETED_PASTE)
|
||||||
|
MODE_GETTER(focus_tracking_enabled, FOCUS_TRACKING)
|
||||||
|
MODE_GETTER(mouse_button_tracking_enabled, MOUSE_BUTTON_TRACKING)
|
||||||
|
MODE_GETTER(mouse_motion_tracking_enabled, MOUSE_MOTION_TRACKING)
|
||||||
|
MODE_GETTER(mouse_in_sgr_mode, MOUSE_SGR_MODE)
|
||||||
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
cursor_up(Screen *self, PyObject *args) {
|
cursor_up(Screen *self, PyObject *args) {
|
||||||
unsigned int count = 1;
|
unsigned int count = 1;
|
||||||
@@ -1059,8 +1042,6 @@ static PyMethodDef methods[] = {
|
|||||||
METHOD(draw, METH_O)
|
METHOD(draw, METH_O)
|
||||||
METHOD(set_mode, METH_VARARGS)
|
METHOD(set_mode, METH_VARARGS)
|
||||||
METHOD(reset_mode, METH_VARARGS)
|
METHOD(reset_mode, METH_VARARGS)
|
||||||
METHOD(focus_tracking_enabled, METH_NOARGS)
|
|
||||||
METHOD(in_bracketed_paste_mode, METH_NOARGS)
|
|
||||||
METHOD(reset, METH_NOARGS)
|
METHOD(reset, METH_NOARGS)
|
||||||
METHOD(reset_dirty, METH_NOARGS)
|
METHOD(reset_dirty, METH_NOARGS)
|
||||||
METHOD(consolidate_changes, METH_NOARGS)
|
METHOD(consolidate_changes, METH_NOARGS)
|
||||||
@@ -1085,6 +1066,11 @@ static PyMethodDef methods[] = {
|
|||||||
MND(mark_as_dirty, METH_NOARGS)
|
MND(mark_as_dirty, METH_NOARGS)
|
||||||
MND(resize, METH_VARARGS)
|
MND(resize, METH_VARARGS)
|
||||||
MND(set_scroll_cell_data, METH_VARARGS)
|
MND(set_scroll_cell_data, METH_VARARGS)
|
||||||
|
MND(in_bracketed_paste, METH_NOARGS)
|
||||||
|
MND(focus_tracking_enabled, METH_NOARGS)
|
||||||
|
MND(mouse_button_tracking_enabled, METH_NOARGS)
|
||||||
|
MND(mouse_motion_tracking_enabled, METH_NOARGS)
|
||||||
|
MND(mouse_in_sgr_mode, METH_NOARGS)
|
||||||
{"update_cell_data", (PyCFunction)screen_update_cell_data, METH_VARARGS, ""},
|
{"update_cell_data", (PyCFunction)screen_update_cell_data, METH_VARARGS, ""},
|
||||||
|
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ class TestParser(BaseTest):
|
|||||||
pb('\033[?2J', ('screen_erase_in_display', 2, 1))
|
pb('\033[?2J', ('screen_erase_in_display', 2, 1))
|
||||||
pb('\033[h')
|
pb('\033[h')
|
||||||
pb('\033[20;4h', ('screen_set_mode', 20), ('screen_set_mode', 4))
|
pb('\033[20;4h', ('screen_set_mode', 20), ('screen_set_mode', 4))
|
||||||
pb('\033[?20;5h', ('screen_set_mode', 20 << 5), ('screen_set_mode', 5 << 5))
|
pb('\033[?1000;1004h', ('screen_set_mode', 1000 << 5), ('screen_set_mode', 1004 << 5))
|
||||||
pb('\033[20;4;145l', ('screen_reset_mode', 20), ('screen_reset_mode', 4), ('screen_reset_mode', 145))
|
pb('\033[20;4;20l', ('screen_reset_mode', 20), ('screen_reset_mode', 4), ('screen_reset_mode', 20))
|
||||||
s.reset()
|
s.reset()
|
||||||
pb('\033[1;3;4;7;9;34;44m', ('select_graphic_rendition', 7))
|
pb('\033[1;3;4;7;9;34;44m', ('select_graphic_rendition', 7))
|
||||||
for attr in 'bold italic reverse strikethrough'.split():
|
for attr in 'bold italic reverse strikethrough'.split():
|
||||||
|
|||||||
Reference in New Issue
Block a user