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

View File

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

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_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 */

View File

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