More work on making Screen native

This commit is contained in:
Kovid Goyal 2016-11-12 15:25:10 +05:30
parent 2c0523246d
commit bead388d81
3 changed files with 188 additions and 0 deletions

65
kitty/control-codes.h Normal file
View File

@ -0,0 +1,65 @@
/*
* control_codes.h
* Copyright (C) 2016 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#pragma once
// Space
#define SP ' '
// *Null*: Does nothing.
#define NUL 0
// *Bell*: Beeps.
#define BEL 0x07
// *Backspace*: Backspace one column, but not past the begining of the
// line.
#define BS 0x08
// *Horizontal tab*: Move cursor to the next tab stop, or to the end
// of the line if there is no earlier tab stop.
#define HT 0x09
// *Linefeed*: Give a line feed, and, if :data:`pyte.modes.LNM` (new
// line mode) is set also a carriage return.
#define LF 10
// *Vertical tab*: Same as :data:`LF`.
#define VT 0x0b
// *Form feed*: Same as :data:`LF`.
#define FF 0x0c
// *Carriage return*: Move cursor to left margin on current line.
#define CR 13
// *Shift out*: Activate G1 character set.
#define SO 0x0e
// *Shift in*: Activate G0 character set.
#define SI 0x0f
// *Cancel*: Interrupt escape sequence. If received during an escape or
// control sequence, cancels the sequence and displays substitution
// character.
#define CAN 0x18
// *Substitute*: Same as :data:`CAN`.
#define SUB 0x1a
// *Escape*: Starts an escape sequence.
#define ESC 0x1b
// *Delete*: Is ignored.
#define DEL 0x7f
// *Control sequence introducer*: An equivalent for ``ESC [``.
#define CSI 0x9b
// *String terminator*.
#define ST 0x9c
// *Operating system command*.
#define OSC 0x9d

View File

@ -209,6 +209,11 @@ typedef struct {
LineBuf *linebuf, *main_linebuf, *alt_linebuf;
ChangeTracker *change_tracker;
ScreenModes modes;
uint8_t parser_buf[8192];
unsigned int parser_state, parser_text_start;
bool parser_has_pending_text;
} Screen;
Line* alloc_line();

View File

@ -6,8 +6,107 @@
*/
#include "data-types.h"
#include "control-codes.h"
extern PyTypeObject Screen_Type;
#define NORMAL_STATE 0
#define ESC_STATE 1
#define CSI_STATE 2
#define OSC_STATE 3
#define DCS_STATE 4
#define DECLARE_CH_SCREEN_HANDLER(name) extern bool screen_##name(Screen *screen, uint8_t ch);
DECLARE_CH_SCREEN_HANDLER(bell)
DECLARE_CH_SCREEN_HANDLER(backspace)
DECLARE_CH_SCREEN_HANDLER(tab)
DECLARE_CH_SCREEN_HANDLER(linefeed)
DECLARE_CH_SCREEN_HANDLER(carriage_return)
DECLARE_CH_SCREEN_HANDLER(shift_out)
DECLARE_CH_SCREEN_HANDLER(shift_in)
extern bool screen_draw(Screen *screen, uint8_t *buf, unsigned int buflen);
static inline bool
read_text(Screen *screen, uint8_t *buf, unsigned int buflen, unsigned int *pos) {
bool ret;
uint8_t ch;
while(*pos < buflen) {
ch = buf[(*pos)++];
#define DRAW_TEXT \
if (screen->parser_has_pending_text) { \
screen->parser_has_pending_text = false; \
ret = screen_draw(screen, buf + screen->parser_text_start, (*pos) - screen->parser_text_start); \
screen->parser_text_start = 0; \
if (!ret) return false; \
}
#define CALL_SCREEN_HANDLER(name) \
DRAW_TEXT; \
if (!screen_##name(screen, ch)) return false;
#define CHANGE_PARSER_STATE(state) screen->parser_state = state; return true;
switch(ch) {
case BEL:
CALL_SCREEN_HANDLER(bell);
case BS:
CALL_SCREEN_HANDLER(backspace);
case HT:
CALL_SCREEN_HANDLER(tab);
case LF:
case VT:
case FF:
CALL_SCREEN_HANDLER(linefeed);
case CR:
CALL_SCREEN_HANDLER(carriage_return);
case SO:
CALL_SCREEN_HANDLER(shift_out);
case SI:
CALL_SCREEN_HANDLER(shift_in);
case ESC:
CHANGE_PARSER_STATE(ESC_STATE);
case CSI:
CHANGE_PARSER_STATE(CSI_STATE);
case NUL:
case DEL:
break;
case OSC:
CHANGE_PARSER_STATE(OSC_STATE);
default:
if (!screen->parser_has_pending_text) {
screen->parser_has_pending_text = true;
screen->parser_text_start = (*pos) - 1;
}
}
}
DRAW_TEXT;
return true;
}
static inline bool
read_esc(Screen *screen, uint8_t *buf, unsigned int buflen, unsigned int *pos) {
screen->parser_state = NORMAL_STATE;
return true;
}
static inline bool
read_csi(Screen *screen, uint8_t *buf, unsigned int buflen, unsigned int *pos) {
screen->parser_state = NORMAL_STATE;
return true;
}
static inline bool
read_osc(Screen *screen, uint8_t *buf, unsigned int buflen, unsigned int *pos) {
screen->parser_state = NORMAL_STATE;
return true;
}
static inline bool
read_dcs(Screen *screen, uint8_t *buf, unsigned int buflen, unsigned int *pos) {
screen->parser_state = NORMAL_STATE;
return true;
}
PyObject*
#ifdef DUMP_COMMANDS
parse_bytes_dump(PyObject UNUSED *self, PyObject *args) {
@ -22,5 +121,24 @@ parse_bytes(PyObject UNUSED *self, PyObject *args) {
#else
if (!PyArg_ParseTuple(args, "O!y*", &Screen_Type, &screen, &pybuf)) return NULL;
#endif
uint8_t *buf = pybuf.buf;
unsigned int i = 0;
#define CALL_HANDLER(name) \
if (!name(screen, buf, pybuf.len, &i)) return NULL; break; \
while (i < pybuf.len) {
switch(screen->parser_state) {
case ESC_STATE:
CALL_HANDLER(read_esc);
case CSI_STATE:
CALL_HANDLER(read_csi);
case OSC_STATE:
CALL_HANDLER(read_osc);
case DCS_STATE:
CALL_HANDLER(read_dcs);
default:
CALL_HANDLER(read_text);
}
}
Py_RETURN_NONE;
}