Clean up the mode handling code

This commit is contained in:
Kovid Goyal 2016-11-24 21:18:04 +05:30
parent d6782d002b
commit 4f5daa94d0
4 changed files with 96 additions and 103 deletions

View File

@ -224,7 +224,9 @@ PyTypeObject ChangeTracker_Type;
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;
PyTypeObject ScreenModes_Type;

View File

@ -23,8 +23,13 @@
// Private modes.
// *Text Cursor Enable Mode*: determines if the text cursor is visible.
#define DECTCEM (25 << 5)
// Arrow keys send application sequences or cursor movement commands
#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.
#define DECSCNM (5 << 5)
@ -39,23 +44,23 @@
// when the cursor is at the right margin.
#define DECAWM (7 << 5)
// *Column Mode*: selects the number of columns per line (80 or 132)
// on the screen.
#define DECCOLM (3 << 5)
// Toggle cursor blinking
#define CONTROL_CURSOR_BLINK (12 << 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
// http://cirw.in/blog/bracketed-paste
#define BRACKETED_PASTE (2004 << 5)
#define BRACKETED_PASTE_START "\033[200~"
#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)

View File

@ -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_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) {
case LNM:
self->modes.mLNM = val; break;
case IRM:
self->modes.mIRM = val; break;
SIMPLE_MODE(LNM)
SIMPLE_MODE(IRM)
SIMPLE_MODE(BRACKETED_PASTE)
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:
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:
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:
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:
self->modes.mDECAWM = val; break;
case DECCOLM:
self->modes.mDECCOLM = val; break;
case BRACKETED_PASTE:
self->modes.mBRACKETED_PASTE = val; break;
case FOCUS_TRACKING:
self->modes.mFOCUS_TRACKING = val; break;
// When DECCOLM mode is set, the screen is erased and the cursor
// moves to the home position.
self->modes.mDECCOLM = val;
screen_erase_in_display(self, 2, false);
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) {
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);
}
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) {
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);
}
// }}}
// Cursor {{{
@ -934,6 +907,16 @@ erase_in_display(Screen *self, PyObject *args) {
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*
cursor_up(Screen *self, PyObject *args) {
unsigned int count = 1;
@ -1059,8 +1042,6 @@ static PyMethodDef methods[] = {
METHOD(draw, METH_O)
METHOD(set_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_dirty, METH_NOARGS)
METHOD(consolidate_changes, METH_NOARGS)
@ -1085,6 +1066,11 @@ static PyMethodDef methods[] = {
MND(mark_as_dirty, METH_NOARGS)
MND(resize, 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, ""},
{NULL} /* Sentinel */

View File

@ -91,8 +91,8 @@ class TestParser(BaseTest):
pb('\033[?2J', ('screen_erase_in_display', 2, 1))
pb('\033[h')
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[20;4;145l', ('screen_reset_mode', 20), ('screen_reset_mode', 4), ('screen_reset_mode', 145))
pb('\033[?1000;1004h', ('screen_set_mode', 1000 << 5), ('screen_set_mode', 1004 << 5))
pb('\033[20;4;20l', ('screen_reset_mode', 20), ('screen_reset_mode', 4), ('screen_reset_mode', 20))
s.reset()
pb('\033[1;3;4;7;9;34;44m', ('select_graphic_rendition', 7))
for attr in 'bold italic reverse strikethrough'.split():