Import libvterm r617.
This commit is contained in:
@@ -44,37 +44,6 @@ static inline void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta
|
||||
rect->start_col += col_delta; rect->end_col += col_delta;
|
||||
}
|
||||
|
||||
/* Flag to indicate non-final subparameters in a single CSI parameter.
|
||||
* Consider
|
||||
* CSI 1;2:3:4;5a
|
||||
* 1 4 and 5 are final.
|
||||
* 2 and 3 are non-final and will have this bit set
|
||||
*
|
||||
* Don't confuse this with the final byte of the CSI escape; 'a' in this case.
|
||||
*/
|
||||
#define CSI_ARG_FLAG_MORE (1<<31)
|
||||
#define CSI_ARG_MASK (~(1<<31))
|
||||
|
||||
#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE)
|
||||
#define CSI_ARG(a) ((a) & CSI_ARG_MASK)
|
||||
|
||||
/* Can't use -1 to indicate a missing argument; use this instead */
|
||||
#define CSI_ARG_MISSING ((1UL<<31)-1)
|
||||
|
||||
#define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING)
|
||||
#define CSI_ARG_OR(a,def) (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a))
|
||||
#define CSI_ARG_COUNT(a) (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a))
|
||||
|
||||
typedef struct {
|
||||
int (*text)(const char *bytes, size_t len, void *user);
|
||||
int (*control)(unsigned char control, void *user);
|
||||
int (*escape)(const char *bytes, size_t len, void *user);
|
||||
int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
|
||||
int (*osc)(const char *command, size_t cmdlen, void *user);
|
||||
int (*dcs)(const char *command, size_t cmdlen, void *user);
|
||||
int (*resize)(int rows, int cols, void *user);
|
||||
} VTermParserCallbacks;
|
||||
|
||||
typedef struct {
|
||||
uint8_t red, green, blue;
|
||||
} VTermColor;
|
||||
@@ -121,33 +90,23 @@ typedef enum {
|
||||
enum {
|
||||
VTERM_PROP_CURSORSHAPE_BLOCK = 1,
|
||||
VTERM_PROP_CURSORSHAPE_UNDERLINE,
|
||||
VTERM_PROP_CURSORSHAPE_BAR_LEFT,
|
||||
};
|
||||
|
||||
typedef void (*VTermMouseFunc)(int x, int y, int button, int pressed, int modifiers, void *data);
|
||||
|
||||
typedef struct {
|
||||
int (*putglyph)(const uint32_t chars[], int width, VTermPos pos, void *user);
|
||||
int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
|
||||
int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user);
|
||||
int (*moverect)(VTermRect dest, VTermRect src, void *user);
|
||||
int (*erase)(VTermRect rect, void *user);
|
||||
int (*initpen)(void *user);
|
||||
int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user);
|
||||
int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
|
||||
int (*setmousefunc)(VTermMouseFunc func, void *data, void *user);
|
||||
int (*bell)(void *user);
|
||||
int (*resize)(int rows, int cols, void *user);
|
||||
} VTermStateCallbacks;
|
||||
const uint32_t *chars;
|
||||
int width;
|
||||
unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */
|
||||
unsigned int dwl:1; /* DECDWL or DECDHL double-width line */
|
||||
unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */
|
||||
} VTermGlyphInfo;
|
||||
|
||||
typedef struct {
|
||||
int (*damage)(VTermRect rect, void *user);
|
||||
int (*moverect)(VTermRect dest, VTermRect src, void *user);
|
||||
int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
|
||||
int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
|
||||
int (*setmousefunc)(VTermMouseFunc func, void *data, void *user);
|
||||
int (*bell)(void *user);
|
||||
int (*resize)(int rows, int cols, void *user);
|
||||
} VTermScreenCallbacks;
|
||||
unsigned int doublewidth:1; /* DECDWL or DECDHL line */
|
||||
unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */
|
||||
} VTermLineInfo;
|
||||
|
||||
typedef struct {
|
||||
/* libvterm relies on this memory to be zeroed out before it is returned
|
||||
@@ -160,22 +119,127 @@ VTerm *vterm_new(int rows, int cols);
|
||||
VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata);
|
||||
void vterm_free(VTerm* vt);
|
||||
|
||||
void vterm_get_size(VTerm *vt, int *rowsp, int *colsp);
|
||||
void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp);
|
||||
void vterm_set_size(VTerm *vt, int rows, int cols);
|
||||
|
||||
void vterm_push_bytes(VTerm *vt, const char *bytes, size_t len);
|
||||
|
||||
void vterm_input_push_char(VTerm *vt, VTermModifier state, uint32_t c);
|
||||
void vterm_input_push_key(VTerm *vt, VTermModifier state, VTermKey key);
|
||||
|
||||
size_t vterm_output_bufferlen(VTerm *vt); /* deprecated */
|
||||
|
||||
size_t vterm_output_get_buffer_size(const VTerm *vt);
|
||||
size_t vterm_output_get_buffer_current(const VTerm *vt);
|
||||
size_t vterm_output_get_buffer_remaining(const VTerm *vt);
|
||||
|
||||
size_t vterm_output_bufferread(VTerm *vt, char *buffer, size_t len);
|
||||
|
||||
// ------------
|
||||
// Parser layer
|
||||
// ------------
|
||||
|
||||
/* Flag to indicate non-final subparameters in a single CSI parameter.
|
||||
* Consider
|
||||
* CSI 1;2:3:4;5a
|
||||
* 1 4 and 5 are final.
|
||||
* 2 and 3 are non-final and will have this bit set
|
||||
*
|
||||
* Don't confuse this with the final byte of the CSI escape; 'a' in this case.
|
||||
*/
|
||||
#define CSI_ARG_FLAG_MORE (1<<31)
|
||||
#define CSI_ARG_MASK (~(1<<31))
|
||||
|
||||
#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE)
|
||||
#define CSI_ARG(a) ((a) & CSI_ARG_MASK)
|
||||
|
||||
/* Can't use -1 to indicate a missing argument; use this instead */
|
||||
#define CSI_ARG_MISSING ((1UL<<31)-1)
|
||||
|
||||
#define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING)
|
||||
#define CSI_ARG_OR(a,def) (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a))
|
||||
#define CSI_ARG_COUNT(a) (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a))
|
||||
|
||||
typedef struct {
|
||||
int (*text)(const char *bytes, size_t len, void *user);
|
||||
int (*control)(unsigned char control, void *user);
|
||||
int (*escape)(const char *bytes, size_t len, void *user);
|
||||
int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
|
||||
int (*osc)(const char *command, size_t cmdlen, void *user);
|
||||
int (*dcs)(const char *command, size_t cmdlen, void *user);
|
||||
int (*resize)(int rows, int cols, void *user);
|
||||
} VTermParserCallbacks;
|
||||
|
||||
void vterm_set_parser_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user);
|
||||
|
||||
void vterm_parser_set_utf8(VTerm *vt, int is_utf8);
|
||||
|
||||
// -----------
|
||||
// State layer
|
||||
// -----------
|
||||
|
||||
typedef struct {
|
||||
int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user);
|
||||
int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
|
||||
int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user);
|
||||
int (*moverect)(VTermRect dest, VTermRect src, void *user);
|
||||
int (*erase)(VTermRect rect, int selective, void *user);
|
||||
int (*initpen)(void *user);
|
||||
int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user);
|
||||
int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
|
||||
int (*setmousefunc)(VTermMouseFunc func, void *data, void *user);
|
||||
int (*bell)(void *user);
|
||||
int (*resize)(int rows, int cols, VTermPos *delta, void *user);
|
||||
int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user);
|
||||
} VTermStateCallbacks;
|
||||
|
||||
VTermState *vterm_obtain_state(VTerm *vt);
|
||||
|
||||
void vterm_state_reset(VTermState *state, int hard);
|
||||
void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user);
|
||||
void vterm_state_get_cursorpos(VTermState *state, VTermPos *cursorpos);
|
||||
void vterm_state_set_default_colors(VTermState *state, VTermColor *default_fg, VTermColor *default_bg);
|
||||
void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos);
|
||||
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg);
|
||||
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col);
|
||||
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg);
|
||||
void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col);
|
||||
void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright);
|
||||
int vterm_state_get_penattr(VTermState *state, VTermAttr attr, VTermValue *val);
|
||||
int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val);
|
||||
int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val);
|
||||
const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row);
|
||||
|
||||
VTermValueType vterm_get_attr_type(VTermAttr attr);
|
||||
VTermValueType vterm_get_prop_type(VTermProp prop);
|
||||
// ------------
|
||||
// Screen layer
|
||||
// ------------
|
||||
|
||||
typedef struct {
|
||||
#define VTERM_MAX_CHARS_PER_CELL 6
|
||||
uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
|
||||
char width;
|
||||
struct {
|
||||
unsigned int bold : 1;
|
||||
unsigned int underline : 2;
|
||||
unsigned int italic : 1;
|
||||
unsigned int blink : 1;
|
||||
unsigned int reverse : 1;
|
||||
unsigned int strike : 1;
|
||||
unsigned int font : 4; /* 0 to 9 */
|
||||
unsigned int dwl : 1; /* On a DECDWL or DECDHL line */
|
||||
unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */
|
||||
} attrs;
|
||||
VTermColor fg, bg;
|
||||
} VTermScreenCell;
|
||||
|
||||
typedef struct {
|
||||
int (*damage)(VTermRect rect, void *user);
|
||||
int (*moverect)(VTermRect dest, VTermRect src, void *user);
|
||||
int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
|
||||
int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
|
||||
int (*setmousefunc)(VTermMouseFunc func, void *data, void *user);
|
||||
int (*bell)(void *user);
|
||||
int (*resize)(int rows, int cols, void *user);
|
||||
int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user);
|
||||
int (*sb_popline)(int cols, VTermScreenCell *cells, void *user);
|
||||
} VTermScreenCallbacks;
|
||||
|
||||
VTermScreen *vterm_obtain_screen(VTerm *vt);
|
||||
|
||||
@@ -193,48 +257,41 @@ void vterm_screen_flush_damage(VTermScreen *screen);
|
||||
void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size);
|
||||
|
||||
void vterm_screen_reset(VTermScreen *screen, int hard);
|
||||
size_t vterm_screen_get_chars(VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect);
|
||||
size_t vterm_screen_get_text(VTermScreen *screen, char *str, size_t len, const VTermRect rect);
|
||||
|
||||
typedef struct {
|
||||
#define VTERM_MAX_CHARS_PER_CELL 6
|
||||
uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
|
||||
char width;
|
||||
struct {
|
||||
unsigned int bold : 1;
|
||||
unsigned int underline : 2;
|
||||
unsigned int italic : 1;
|
||||
unsigned int blink : 1;
|
||||
unsigned int reverse : 1;
|
||||
unsigned int strike : 1;
|
||||
unsigned int font : 4; /* 0 to 9 */
|
||||
} attrs;
|
||||
VTermColor fg, bg;
|
||||
} VTermScreenCell;
|
||||
/* Neither of these functions NUL-terminate the buffer */
|
||||
size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect);
|
||||
size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect);
|
||||
|
||||
void vterm_screen_get_cell(VTermScreen *screen, VTermPos pos, VTermScreenCell *cell);
|
||||
typedef enum {
|
||||
VTERM_ATTR_BOLD_MASK = 1 << 0,
|
||||
VTERM_ATTR_UNDERLINE_MASK = 1 << 1,
|
||||
VTERM_ATTR_ITALIC_MASK = 1 << 2,
|
||||
VTERM_ATTR_BLINK_MASK = 1 << 3,
|
||||
VTERM_ATTR_REVERSE_MASK = 1 << 4,
|
||||
VTERM_ATTR_STRIKE_MASK = 1 << 5,
|
||||
VTERM_ATTR_FONT_MASK = 1 << 6,
|
||||
VTERM_ATTR_FOREGROUND_MASK = 1 << 7,
|
||||
VTERM_ATTR_BACKGROUND_MASK = 1 << 8,
|
||||
} VTermAttrMask;
|
||||
|
||||
int vterm_screen_is_eol(VTermScreen *screen, VTermPos pos);
|
||||
int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs);
|
||||
|
||||
void vterm_input_push_char(VTerm *vt, VTermModifier state, uint32_t c);
|
||||
void vterm_input_push_key(VTerm *vt, VTermModifier state, VTermKey key);
|
||||
int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell);
|
||||
|
||||
void vterm_parser_set_utf8(VTerm *vt, int is_utf8);
|
||||
void vterm_push_bytes(VTerm *vt, const char *bytes, size_t len);
|
||||
int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos);
|
||||
|
||||
size_t vterm_output_bufferlen(VTerm *vt); /* deprecated */
|
||||
// ---------
|
||||
// Utilities
|
||||
// ---------
|
||||
|
||||
size_t vterm_output_get_buffer_size(VTerm *vt);
|
||||
size_t vterm_output_get_buffer_current(VTerm *vt);
|
||||
size_t vterm_output_get_buffer_remaining(VTerm *vt);
|
||||
|
||||
size_t vterm_output_bufferread(VTerm *vt, char *buffer, size_t len);
|
||||
VTermValueType vterm_get_attr_type(VTermAttr attr);
|
||||
VTermValueType vterm_get_prop_type(VTermProp prop);
|
||||
|
||||
void vterm_scroll_rect(VTermRect rect,
|
||||
int downward,
|
||||
int rightward,
|
||||
int (*moverect)(VTermRect src, VTermRect dest, void *user),
|
||||
int (*eraserect)(VTermRect rect, void *user),
|
||||
int (*eraserect)(VTermRect rect, int selective, void *user),
|
||||
void *user);
|
||||
|
||||
void vterm_copy_cells(VTermRect dest,
|
||||
|
||||
@@ -28,9 +28,28 @@ typedef enum {
|
||||
VTERM_KEY_PAGEUP,
|
||||
VTERM_KEY_PAGEDOWN,
|
||||
|
||||
VTERM_KEY_FUNCTION_0,
|
||||
VTERM_KEY_FUNCTION_0 = 256,,
|
||||
VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255,
|
||||
|
||||
VTERM_KEY_KP_0,
|
||||
VTERM_KEY_KP_1,
|
||||
VTERM_KEY_KP_2,
|
||||
VTERM_KEY_KP_3,
|
||||
VTERM_KEY_KP_4,
|
||||
VTERM_KEY_KP_5,
|
||||
VTERM_KEY_KP_6,
|
||||
VTERM_KEY_KP_7,
|
||||
VTERM_KEY_KP_8,
|
||||
VTERM_KEY_KP_9,
|
||||
VTERM_KEY_KP_MULT,
|
||||
VTERM_KEY_KP_PLUS,
|
||||
VTERM_KEY_KP_COMMA,
|
||||
VTERM_KEY_KP_MINUS,
|
||||
VTERM_KEY_KP_PERIOD,
|
||||
VTERM_KEY_KP_DIVIDE,
|
||||
VTERM_KEY_KP_ENTER,
|
||||
VTERM_KEY_KP_EQUAL,
|
||||
|
||||
VTERM_KEY_MAX, // Must be last
|
||||
} VTermKey;
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#include "vterm_internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define UNICODE_INVALID 0xFFFD
|
||||
|
||||
#ifdef DEBUG
|
||||
#if defined(DEBUG) && DEBUG > 1
|
||||
# define DEBUG_PRINT_UTF8
|
||||
#endif
|
||||
|
||||
@@ -37,7 +35,7 @@ static void decode_utf8(VTermEncoding *enc, void *data_,
|
||||
printf("BEGIN UTF-8\n");
|
||||
#endif
|
||||
|
||||
for( ; *pos < bytelen; (*pos)++) {
|
||||
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
|
||||
unsigned char c = bytes[*pos];
|
||||
|
||||
#ifdef DEBUG_PRINT_UTF8
|
||||
@@ -157,8 +155,10 @@ static void decode_usascii(VTermEncoding *enc, void *data,
|
||||
uint32_t cp[], int *cpi, int cplen,
|
||||
const char bytes[], size_t *pos, size_t bytelen)
|
||||
{
|
||||
for(; *pos < bytelen; (*pos)++) {
|
||||
unsigned char c = bytes[*pos];
|
||||
int is_gr = bytes[*pos] & 0x80;
|
||||
|
||||
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
|
||||
unsigned char c = bytes[*pos] ^ is_gr;
|
||||
|
||||
if(c < 0x20 || c >= 0x80)
|
||||
return;
|
||||
@@ -181,11 +181,12 @@ static void decode_table(VTermEncoding *enc, void *data,
|
||||
const char bytes[], size_t *pos, size_t bytelen)
|
||||
{
|
||||
struct StaticTableEncoding *table = (struct StaticTableEncoding *)enc;
|
||||
int is_gr = bytes[*pos] & 0x80;
|
||||
|
||||
for(; *pos < bytelen; (*pos)++) {
|
||||
unsigned char c = (bytes[*pos]) & 0x7f;
|
||||
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
|
||||
unsigned char c = bytes[*pos] ^ is_gr;
|
||||
|
||||
if(c < 0x20)
|
||||
if(c < 0x20 || c >= 0x80)
|
||||
return;
|
||||
|
||||
if(table->chars[c])
|
||||
@@ -208,13 +209,13 @@ encodings[] = {
|
||||
{ ENC_SINGLE_94, '0', (VTermEncoding*)&encoding_DECdrawing },
|
||||
{ ENC_SINGLE_94, 'A', (VTermEncoding*)&encoding_uk },
|
||||
{ ENC_SINGLE_94, 'B', &encoding_usascii },
|
||||
{ 0, 0 },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
/* This ought to be INTERNAL but isn't because it's used by unit testing */
|
||||
VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; encodings[i].designation; i++)
|
||||
for(int i = 0; encodings[i].designation; i++)
|
||||
if(encodings[i].type == type && encodings[i].designation == designation)
|
||||
return encodings[i].enc;
|
||||
return NULL;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
static const struct StaticTableEncoding encoding_DECdrawing = {
|
||||
{ .decode = &decode_table },
|
||||
{
|
||||
[0x60] = 0x25C6,
|
||||
[0x61] = 0x2592,
|
||||
[0x62] = 0x2409,
|
||||
[0x63] = 0x240C,
|
||||
[0x64] = 0x240D,
|
||||
[0x65] = 0x240A,
|
||||
[0x66] = 0x00B0,
|
||||
[0x67] = 0x00B1,
|
||||
[0x68] = 0x2424,
|
||||
[0x69] = 0x240B,
|
||||
[0x6a] = 0x2518,
|
||||
[0x6b] = 0x2510,
|
||||
[0x6c] = 0x250C,
|
||||
[0x6d] = 0x2514,
|
||||
[0x6e] = 0x253C,
|
||||
[0x6f] = 0x23BA,
|
||||
[0x70] = 0x23BB,
|
||||
[0x71] = 0x2500,
|
||||
[0x72] = 0x23BC,
|
||||
[0x73] = 0x23BD,
|
||||
[0x74] = 0x251C,
|
||||
[0x75] = 0x2524,
|
||||
[0x76] = 0x2534,
|
||||
[0x77] = 0x252C,
|
||||
[0x78] = 0x2502,
|
||||
[0x79] = 0x2A7D,
|
||||
[0x7a] = 0x2A7E,
|
||||
[0x7b] = 0x03C0,
|
||||
[0x7c] = 0x2260,
|
||||
[0x7d] = 0x00A3,
|
||||
[0x7e] = 0x00B7,
|
||||
}
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
static const struct StaticTableEncoding encoding_uk = {
|
||||
{ .decode = &decode_table },
|
||||
{
|
||||
[0x23] = 0x00a3,
|
||||
}
|
||||
};
|
||||
@@ -6,17 +6,11 @@
|
||||
|
||||
void vterm_input_push_char(VTerm *vt, VTermModifier mod, uint32_t c)
|
||||
{
|
||||
int needs_CSIu;
|
||||
/* The shift modifier is never important for Unicode characters
|
||||
* apart from Space
|
||||
*/
|
||||
if(c != ' ')
|
||||
mod &= ~VTERM_MOD_SHIFT;
|
||||
/* However, since Shift-Space is too easy to mistype accidentally, remove
|
||||
* shift if it's the only modifier
|
||||
*/
|
||||
else if(mod == VTERM_MOD_SHIFT)
|
||||
mod = 0;
|
||||
|
||||
if(mod == 0) {
|
||||
// Normal text - ignore just shift
|
||||
@@ -26,6 +20,7 @@ void vterm_input_push_char(VTerm *vt, VTermModifier mod, uint32_t c)
|
||||
return;
|
||||
}
|
||||
|
||||
int needs_CSIu;
|
||||
switch(c) {
|
||||
/* Special Ctrl- letters that can't be represented elsewise */
|
||||
case 'h': case 'i': case 'j': case 'm': case '[':
|
||||
@@ -42,7 +37,7 @@ void vterm_input_push_char(VTerm *vt, VTermModifier mod, uint32_t c)
|
||||
|
||||
/* ALT we can just prefix with ESC; anything else requires CSI u */
|
||||
if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) {
|
||||
vterm_push_output_sprintf(vt, "\e[%d;%du", c, mod+1);
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,15 +53,17 @@ typedef struct {
|
||||
KEYCODE_LITERAL,
|
||||
KEYCODE_TAB,
|
||||
KEYCODE_ENTER,
|
||||
KEYCODE_SS3,
|
||||
KEYCODE_CSI,
|
||||
KEYCODE_CSI_CURSOR,
|
||||
KEYCODE_CSINUM,
|
||||
KEYCODE_KEYPAD,
|
||||
} type;
|
||||
char literal;
|
||||
int csinum;
|
||||
} keycodes_s;
|
||||
|
||||
keycodes_s keycodes[] = {
|
||||
static keycodes_s keycodes[] = {
|
||||
{ KEYCODE_NONE }, // NONE
|
||||
|
||||
{ KEYCODE_ENTER, '\r' }, // ENTER
|
||||
@@ -85,7 +82,9 @@ keycodes_s keycodes[] = {
|
||||
{ KEYCODE_CSI_CURSOR, 'F' }, // END
|
||||
{ KEYCODE_CSINUM, '~', 5 }, // PAGEUP
|
||||
{ KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN
|
||||
};
|
||||
|
||||
static keycodes_s keycodes_fn[] = {
|
||||
{ KEYCODE_NONE }, // F0 - shouldn't happen
|
||||
{ KEYCODE_CSI_CURSOR, 'P' }, // F1
|
||||
{ KEYCODE_CSI_CURSOR, 'Q' }, // F2
|
||||
@@ -101,22 +100,48 @@ keycodes_s keycodes[] = {
|
||||
{ KEYCODE_CSINUM, '~', 24 }, // F12
|
||||
};
|
||||
|
||||
static keycodes_s keycodes_kp[] = {
|
||||
{ KEYCODE_KEYPAD, '0', 'p' }, // KP_0
|
||||
{ KEYCODE_KEYPAD, '1', 'q' }, // KP_1
|
||||
{ KEYCODE_KEYPAD, '2', 'r' }, // KP_2
|
||||
{ KEYCODE_KEYPAD, '3', 's' }, // KP_3
|
||||
{ KEYCODE_KEYPAD, '4', 't' }, // KP_4
|
||||
{ KEYCODE_KEYPAD, '5', 'u' }, // KP_5
|
||||
{ KEYCODE_KEYPAD, '6', 'v' }, // KP_6
|
||||
{ KEYCODE_KEYPAD, '7', 'w' }, // KP_7
|
||||
{ KEYCODE_KEYPAD, '8', 'x' }, // KP_8
|
||||
{ KEYCODE_KEYPAD, '9', 'y' }, // KP_9
|
||||
{ KEYCODE_KEYPAD, '*', 'j' }, // KP_MULT
|
||||
{ KEYCODE_KEYPAD, '+', 'k' }, // KP_PLUS
|
||||
{ KEYCODE_KEYPAD, ',', 'l' }, // KP_COMMA
|
||||
{ KEYCODE_KEYPAD, '-', 'm' }, // KP_MINUS
|
||||
{ KEYCODE_KEYPAD, '.', 'n' }, // KP_PERIOD
|
||||
{ KEYCODE_KEYPAD, '/', 'o' }, // KP_DIVIDE
|
||||
{ KEYCODE_KEYPAD, '\n', 'M' }, // KP_ENTER
|
||||
{ KEYCODE_KEYPAD, '=', 'X' }, // KP_EQUAL
|
||||
};
|
||||
|
||||
void vterm_input_push_key(VTerm *vt, VTermModifier mod, VTermKey key)
|
||||
{
|
||||
if(key == VTERM_KEY_NONE)
|
||||
return;
|
||||
|
||||
keycodes_s k;
|
||||
/* Since Shift-Enter and Shift-Backspace are too easy to mistype
|
||||
* accidentally, remove shift if it's the only modifier
|
||||
*/
|
||||
if((key == VTERM_KEY_ENTER || key == VTERM_KEY_BACKSPACE) && mod == VTERM_MOD_SHIFT)
|
||||
mod = 0;
|
||||
|
||||
if(key == VTERM_KEY_NONE || key >= VTERM_KEY_MAX)
|
||||
return;
|
||||
|
||||
if(key >= sizeof(keycodes)/sizeof(keycodes[0]))
|
||||
return;
|
||||
|
||||
k = keycodes[key];
|
||||
if(key < VTERM_KEY_FUNCTION_0) {
|
||||
if(key >= sizeof(keycodes)/sizeof(keycodes[0]))
|
||||
return;
|
||||
k = keycodes[key];
|
||||
}
|
||||
else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) {
|
||||
if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0]))
|
||||
return;
|
||||
k = keycodes_fn[key - VTERM_KEY_FUNCTION_0];
|
||||
}
|
||||
else if(key >= VTERM_KEY_KP_0) {
|
||||
if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0]))
|
||||
return;
|
||||
k = keycodes_kp[key - VTERM_KEY_KP_0];
|
||||
}
|
||||
|
||||
switch(k.type) {
|
||||
case KEYCODE_NONE:
|
||||
@@ -125,11 +150,11 @@ void vterm_input_push_key(VTerm *vt, VTermModifier mod, VTermKey key)
|
||||
case KEYCODE_TAB:
|
||||
/* Shift-Tab is CSI Z but plain Tab is 0x09 */
|
||||
if(mod == VTERM_MOD_SHIFT)
|
||||
vterm_push_output_sprintf(vt, "\e[Z");
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z");
|
||||
else if(mod & VTERM_MOD_SHIFT)
|
||||
vterm_push_output_sprintf(vt, "\e[1;%dZ", mod+1);
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1);
|
||||
else
|
||||
goto literal;
|
||||
goto case_LITERAL;
|
||||
break;
|
||||
|
||||
case KEYCODE_ENTER:
|
||||
@@ -137,35 +162,49 @@ void vterm_input_push_key(VTerm *vt, VTermModifier mod, VTermKey key)
|
||||
if(vt->state->mode.newline)
|
||||
vterm_push_output_sprintf(vt, "\r\n");
|
||||
else
|
||||
goto literal;
|
||||
goto case_LITERAL;
|
||||
break;
|
||||
|
||||
literal:
|
||||
case KEYCODE_LITERAL:
|
||||
case KEYCODE_LITERAL: case_LITERAL:
|
||||
if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL))
|
||||
vterm_push_output_sprintf(vt, "\e[%d;%du", k.literal, mod+1);
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1);
|
||||
else
|
||||
vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? "\e%c" : "%c", k.literal);
|
||||
break;
|
||||
|
||||
case KEYCODE_CSI_CURSOR:
|
||||
if(vt->state->mode.cursor && mod == 0) {
|
||||
vterm_push_output_sprintf(vt, "\eO%c", k.literal);
|
||||
break;
|
||||
}
|
||||
/* else FALLTHROUGH */
|
||||
case KEYCODE_CSI:
|
||||
case KEYCODE_SS3: case_SS3:
|
||||
if(mod == 0)
|
||||
vterm_push_output_sprintf(vt, "\e[%c", k.literal);
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal);
|
||||
else
|
||||
vterm_push_output_sprintf(vt, "\e[1;%d%c", mod + 1, k.literal);
|
||||
goto case_CSI;
|
||||
break;
|
||||
|
||||
case KEYCODE_CSI: case_CSI:
|
||||
if(mod == 0)
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal);
|
||||
else
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal);
|
||||
break;
|
||||
|
||||
case KEYCODE_CSINUM:
|
||||
if(mod == 0)
|
||||
vterm_push_output_sprintf(vt, "\e[%d%c", k.csinum, k.literal);
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal);
|
||||
else
|
||||
vterm_push_output_sprintf(vt, "\e[%d;%d%c", k.csinum, mod + 1, k.literal);
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal);
|
||||
break;
|
||||
|
||||
case KEYCODE_CSI_CURSOR:
|
||||
if(vt->state->mode.cursor)
|
||||
goto case_SS3;
|
||||
else
|
||||
goto case_CSI;
|
||||
|
||||
case KEYCODE_KEYPAD:
|
||||
if(vt->state->mode.keypad) {
|
||||
k.literal = k.csinum;
|
||||
goto case_SS3;
|
||||
}
|
||||
else
|
||||
goto case_LITERAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "vterm_internal.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -19,15 +18,10 @@ static void do_control(VTerm *vt, unsigned char control)
|
||||
|
||||
static void do_string_csi(VTerm *vt, const char *args, size_t arglen, char command)
|
||||
{
|
||||
size_t i = 0;
|
||||
int i = 0;
|
||||
|
||||
int leaderlen = 0;
|
||||
char leader[CSI_LEADER_MAX];
|
||||
int argcount = 1; // Always at least 1 arg
|
||||
long csi_args[CSI_ARGS_MAX];
|
||||
int argi;
|
||||
int intermedlen = 0;
|
||||
char intermed[CSI_INTERMED_MAX];
|
||||
|
||||
// Extract leader bytes 0x3c to 0x3f
|
||||
for( ; i < arglen; i++) {
|
||||
@@ -39,14 +33,18 @@ static void do_string_csi(VTerm *vt, const char *args, size_t arglen, char comma
|
||||
|
||||
leader[leaderlen] = 0;
|
||||
|
||||
int argcount = 1; // Always at least 1 arg
|
||||
|
||||
for( ; i < arglen; i++)
|
||||
if(args[i] == 0x3b || args[i] == 0x3a) // ; or :
|
||||
argcount++;
|
||||
|
||||
/* TODO: Consider if these buffers should live in the VTerm struct itself */
|
||||
long csi_args[CSI_ARGS_MAX];
|
||||
if(argcount > CSI_ARGS_MAX)
|
||||
argcount = CSI_ARGS_MAX;
|
||||
|
||||
int argi;
|
||||
for(argi = 0; argi < argcount; argi++)
|
||||
csi_args[argi] = CSI_ARG_MISSING;
|
||||
|
||||
@@ -72,6 +70,8 @@ static void do_string_csi(VTerm *vt, const char *args, size_t arglen, char comma
|
||||
}
|
||||
done_leader: ;
|
||||
|
||||
int intermedlen = 0;
|
||||
char intermed[CSI_INTERMED_MAX];
|
||||
|
||||
for( ; i < arglen; i++) {
|
||||
if((args[i] & 0xf0) != 0x20)
|
||||
@@ -118,8 +118,6 @@ static void append_strbuffer(VTerm *vt, const char *str, size_t len)
|
||||
|
||||
static size_t do_string(VTerm *vt, const char *str_frag, size_t len)
|
||||
{
|
||||
size_t eaten;
|
||||
|
||||
if(vt->strbuffer_cur) {
|
||||
if(str_frag)
|
||||
append_strbuffer(vt, str_frag, len);
|
||||
@@ -134,6 +132,8 @@ static size_t do_string(VTerm *vt, const char *str_frag, size_t len)
|
||||
|
||||
vt->strbuffer_cur = 0;
|
||||
|
||||
size_t eaten;
|
||||
|
||||
switch(vt->parser_state) {
|
||||
case NORMAL:
|
||||
if(vt->parser_callbacks && vt->parser_callbacks->text)
|
||||
@@ -190,7 +190,7 @@ static size_t do_string(VTerm *vt, const char *str_frag, size_t len)
|
||||
void vterm_push_bytes(VTerm *vt, const char *bytes, size_t len)
|
||||
{
|
||||
size_t pos = 0;
|
||||
const char *string_start = NULL;
|
||||
const char *string_start;
|
||||
|
||||
switch(vt->parser_state) {
|
||||
case NORMAL:
|
||||
@@ -299,14 +299,14 @@ void vterm_push_bytes(VTerm *vt, const char *bytes, size_t len)
|
||||
|
||||
case OSC:
|
||||
case DCS:
|
||||
if(c == 0x07 || (c == 0x9c && !vt->is_utf8)) {
|
||||
if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) {
|
||||
do_string(vt, string_start, bytes + pos - string_start);
|
||||
ENTER_NORMAL_STATE();
|
||||
}
|
||||
break;
|
||||
|
||||
case NORMAL:
|
||||
if(c >= 0x80 && c < 0xa0 && !vt->is_utf8) {
|
||||
if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) {
|
||||
switch(c) {
|
||||
case 0x90: // DCS
|
||||
ENTER_STRING_STATE(DCS);
|
||||
|
||||
@@ -33,17 +33,39 @@ static int ramp24[] = {
|
||||
0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF,
|
||||
};
|
||||
|
||||
static void lookup_colour_ansi(long index, char is_bg, VTermColor *col)
|
||||
static void lookup_colour_ansi(const VTermState *state, long index, VTermColor *col)
|
||||
{
|
||||
if(index >= 0 && index < 16) {
|
||||
*col = ansi_colors[index];
|
||||
*col = state->colors[index];
|
||||
}
|
||||
}
|
||||
|
||||
static int lookup_colour(int palette, const long args[], int argcount, char is_bg, VTermColor *col)
|
||||
static void lookup_colour_palette(const VTermState *state, long index, VTermColor *col)
|
||||
{
|
||||
long index;
|
||||
if(index >= 0 && index < 16) {
|
||||
// Normal 8 colours or high intensity - parse as palette 0
|
||||
lookup_colour_ansi(state, index, col);
|
||||
}
|
||||
else if(index >= 16 && index < 232) {
|
||||
// 216-colour cube
|
||||
index -= 16;
|
||||
|
||||
col->blue = ramp6[index % 6];
|
||||
col->green = ramp6[index/6 % 6];
|
||||
col->red = ramp6[index/6/6 % 6];
|
||||
}
|
||||
else if(index >= 232 && index < 256) {
|
||||
// 24 greyscales
|
||||
index -= 232;
|
||||
|
||||
col->red = ramp24[index];
|
||||
col->green = ramp24[index];
|
||||
col->blue = ramp24[index];
|
||||
}
|
||||
}
|
||||
|
||||
static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col, int *index)
|
||||
{
|
||||
switch(palette) {
|
||||
case 2: // RGB mode - 3 args contain colour values directly
|
||||
if(argcount < 3)
|
||||
@@ -56,28 +78,10 @@ static int lookup_colour(int palette, const long args[], int argcount, char is_b
|
||||
return 3;
|
||||
|
||||
case 5: // XTerm 256-colour mode
|
||||
index = argcount ? CSI_ARG_OR(args[0], -1) : -1;
|
||||
if(index)
|
||||
*index = CSI_ARG_OR(args[0], -1);
|
||||
|
||||
if(index >= 0 && index < 16) {
|
||||
// Normal 8 colours or high intensity - parse as palette 0
|
||||
lookup_colour_ansi(index, is_bg, col);
|
||||
}
|
||||
else if(index >= 16 && index < 232) {
|
||||
// 216-colour cube
|
||||
index -= 16;
|
||||
|
||||
col->blue = ramp6[index % 6];
|
||||
col->green = ramp6[index/6 % 6];
|
||||
col->red = ramp6[index/6/6 % 6];
|
||||
}
|
||||
else if(index >= 232 && index < 256) {
|
||||
// 24 greyscales
|
||||
index -= 232;
|
||||
|
||||
col->red = ramp24[index];
|
||||
col->green = ramp24[index];
|
||||
col->blue = ramp24[index];
|
||||
}
|
||||
lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col);
|
||||
|
||||
return argcount ? 1 : 0;
|
||||
|
||||
@@ -124,12 +128,22 @@ static void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col)
|
||||
{
|
||||
VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg;
|
||||
|
||||
lookup_colour_ansi(col, attr == VTERM_ATTR_BACKGROUND, colp);
|
||||
lookup_colour_ansi(state, col, colp);
|
||||
|
||||
setpenattr_col(state, attr, *colp);
|
||||
}
|
||||
|
||||
void vterm_state_resetpen(VTermState *state)
|
||||
INTERNAL void vterm_state_newpen(VTermState *state)
|
||||
{
|
||||
// 90% grey so that pure white is brighter
|
||||
state->default_fg.red = state->default_fg.green = state->default_fg.blue = 240;
|
||||
state->default_bg.red = state->default_bg.green = state->default_bg.blue = 0;
|
||||
|
||||
for(int col = 0; col < 16; col++)
|
||||
state->colors[col] = ansi_colors[col];
|
||||
}
|
||||
|
||||
INTERNAL void vterm_state_resetpen(VTermState *state)
|
||||
{
|
||||
state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0);
|
||||
state->pen.underline = 0; setpenattr_int( state, VTERM_ATTR_UNDERLINE, 0);
|
||||
@@ -139,12 +153,13 @@ void vterm_state_resetpen(VTermState *state)
|
||||
state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);
|
||||
state->pen.font = 0; setpenattr_int( state, VTERM_ATTR_FONT, 0);
|
||||
|
||||
state->fg_ansi = -1;
|
||||
state->fg_index = -1;
|
||||
state->bg_index = -1;
|
||||
state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg);
|
||||
state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg);
|
||||
}
|
||||
|
||||
void vterm_state_savepen(VTermState *state, int save)
|
||||
INTERNAL void vterm_state_savepen(VTermState *state, int save)
|
||||
{
|
||||
if(save) {
|
||||
state->saved.pen = state->pen;
|
||||
@@ -164,18 +179,35 @@ void vterm_state_savepen(VTermState *state, int save)
|
||||
}
|
||||
}
|
||||
|
||||
void vterm_state_set_default_colors(VTermState *state, VTermColor *default_fg, VTermColor *default_bg)
|
||||
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg)
|
||||
{
|
||||
*default_fg = state->default_fg;
|
||||
*default_bg = state->default_bg;
|
||||
}
|
||||
|
||||
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col)
|
||||
{
|
||||
lookup_colour_palette(state, index, col);
|
||||
}
|
||||
|
||||
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg)
|
||||
{
|
||||
state->default_fg = *default_fg;
|
||||
state->default_bg = *default_bg;
|
||||
}
|
||||
|
||||
void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col)
|
||||
{
|
||||
if(index >= 0 && index < 16)
|
||||
state->colors[index] = *col;
|
||||
}
|
||||
|
||||
void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright)
|
||||
{
|
||||
state->bold_is_highbright = bold_is_highbright;
|
||||
}
|
||||
|
||||
void vterm_state_setpen(VTermState *state, const long args[], int argcount)
|
||||
INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount)
|
||||
{
|
||||
// SGR - ECMA-48 8.3.117
|
||||
|
||||
@@ -197,8 +229,8 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount)
|
||||
case 1: // Bold on
|
||||
state->pen.bold = 1;
|
||||
setpenattr_bool(state, VTERM_ATTR_BOLD, 1);
|
||||
if(state->fg_ansi > -1 && state->bold_is_highbright)
|
||||
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, state->fg_ansi + (state->pen.bold ? 8 : 0));
|
||||
if(state->fg_index > -1 && state->fg_index < 8 && state->bold_is_highbright)
|
||||
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, state->fg_index + (state->pen.bold ? 8 : 0));
|
||||
break;
|
||||
|
||||
case 3: // Italic on
|
||||
@@ -270,51 +302,59 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount)
|
||||
case 30: case 31: case 32: case 33:
|
||||
case 34: case 35: case 36: case 37: // Foreground colour palette
|
||||
value = CSI_ARG(args[argi]) - 30;
|
||||
state->fg_ansi = value;
|
||||
state->fg_index = value;
|
||||
if(state->pen.bold && state->bold_is_highbright)
|
||||
value += 8;
|
||||
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);
|
||||
break;
|
||||
|
||||
case 38: // Foreground colour alternative palette
|
||||
state->fg_ansi = -1;
|
||||
state->fg_index = -1;
|
||||
if(argcount - argi < 1)
|
||||
return;
|
||||
argi += 1 + lookup_colour(CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, 0, &state->pen.fg);
|
||||
argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index);
|
||||
setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);
|
||||
break;
|
||||
|
||||
case 39: // Foreground colour default
|
||||
state->fg_ansi = -1;
|
||||
state->fg_index = -1;
|
||||
state->pen.fg = state->default_fg;
|
||||
setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);
|
||||
break;
|
||||
|
||||
case 40: case 41: case 42: case 43:
|
||||
case 44: case 45: case 46: case 47: // Background colour palette
|
||||
set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, CSI_ARG(args[argi]) - 40);
|
||||
value = CSI_ARG(args[argi]) - 40;
|
||||
state->bg_index = value;
|
||||
set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);
|
||||
break;
|
||||
|
||||
case 48: // Background colour alternative palette
|
||||
state->bg_index = -1;
|
||||
if(argcount - argi < 1)
|
||||
return;
|
||||
argi += 1 + lookup_colour(CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, 1, &state->pen.bg);
|
||||
argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index);
|
||||
setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);
|
||||
break;
|
||||
|
||||
case 49: // Default background
|
||||
state->bg_index = -1;
|
||||
state->pen.bg = state->default_bg;
|
||||
setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);
|
||||
break;
|
||||
|
||||
case 90: case 91: case 92: case 93:
|
||||
case 94: case 95: case 96: case 97: // Foreground colour high-intensity palette
|
||||
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, CSI_ARG(args[argi]) - 90 + 8);
|
||||
value = CSI_ARG(args[argi]) - 90 + 8;
|
||||
state->fg_index = value;
|
||||
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);
|
||||
break;
|
||||
|
||||
case 100: case 101: case 102: case 103:
|
||||
case 104: case 105: case 106: case 107: // Background colour high-intensity palette
|
||||
set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, CSI_ARG(args[argi]) - 100 + 8);
|
||||
value = CSI_ARG(args[argi]) - 100 + 8;
|
||||
state->bg_index = value;
|
||||
set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -329,7 +369,58 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount)
|
||||
}
|
||||
}
|
||||
|
||||
int vterm_state_get_penattr(VTermState *state, VTermAttr attr, VTermValue *val)
|
||||
INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount)
|
||||
{
|
||||
int argi = 0;
|
||||
|
||||
if(state->pen.bold)
|
||||
args[argi++] = 1;
|
||||
|
||||
if(state->pen.italic)
|
||||
args[argi++] = 3;
|
||||
|
||||
if(state->pen.underline == 1)
|
||||
args[argi++] = 4;
|
||||
|
||||
if(state->pen.blink)
|
||||
args[argi++] = 5;
|
||||
|
||||
if(state->pen.reverse)
|
||||
args[argi++] = 7;
|
||||
|
||||
if(state->pen.strike)
|
||||
args[argi++] = 9;
|
||||
|
||||
if(state->pen.font)
|
||||
args[argi++] = 10 + state->pen.font;
|
||||
|
||||
if(state->pen.underline == 2)
|
||||
args[argi++] = 21;
|
||||
|
||||
if(state->fg_index >= 0 && state->fg_index < 8)
|
||||
args[argi++] = 30 + state->fg_index;
|
||||
else if(state->fg_index >= 8 && state->fg_index < 16)
|
||||
args[argi++] = 90 + state->fg_index - 8;
|
||||
else if(state->fg_index >= 16 && state->fg_index < 256) {
|
||||
args[argi++] = CSI_ARG_FLAG_MORE|38;
|
||||
args[argi++] = CSI_ARG_FLAG_MORE|5;
|
||||
args[argi++] = state->fg_index;
|
||||
}
|
||||
|
||||
if(state->bg_index >= 0 && state->bg_index < 8)
|
||||
args[argi++] = 40 + state->bg_index;
|
||||
else if(state->bg_index >= 8 && state->bg_index < 16)
|
||||
args[argi++] = 100 + state->bg_index - 8;
|
||||
else if(state->bg_index >= 16 && state->bg_index < 256) {
|
||||
args[argi++] = CSI_ARG_FLAG_MORE|48;
|
||||
args[argi++] = CSI_ARG_FLAG_MORE|5;
|
||||
args[argi++] = state->bg_index;
|
||||
}
|
||||
|
||||
return argi;
|
||||
}
|
||||
|
||||
int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val)
|
||||
{
|
||||
switch(attr) {
|
||||
case VTERM_ATTR_BOLD:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "vterm_internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rect.h"
|
||||
#include "utf8.h"
|
||||
@@ -21,6 +22,11 @@ typedef struct
|
||||
unsigned int reverse : 1;
|
||||
unsigned int strike : 1;
|
||||
unsigned int font : 4; /* 0 to 9 */
|
||||
|
||||
/* Extra state storage that isn't strictly pen-related */
|
||||
unsigned int protected_cell : 1;
|
||||
unsigned int dwl : 1; /* on a DECDWL or DECDHL line */
|
||||
unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */
|
||||
} ScreenPen;
|
||||
|
||||
/* Internal representation of a screen cell */
|
||||
@@ -30,6 +36,8 @@ typedef struct
|
||||
ScreenPen pen;
|
||||
} ScreenCell;
|
||||
|
||||
static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell);
|
||||
|
||||
struct VTermScreen
|
||||
{
|
||||
VTerm *vt;
|
||||
@@ -54,22 +62,27 @@ struct VTermScreen
|
||||
/* buffer will == buffers[0] or buffers[1], depending on altscreen */
|
||||
ScreenCell *buffer;
|
||||
|
||||
/* buffer for a single screen row used in scrollback storage callbacks */
|
||||
VTermScreenCell *sb_buffer;
|
||||
|
||||
ScreenPen pen;
|
||||
};
|
||||
|
||||
static inline ScreenCell *getcell(VTermScreen *screen, int row, int col)
|
||||
static inline ScreenCell *getcell(const VTermScreen *screen, int row, int col)
|
||||
{
|
||||
/* TODO: Bounds checking */
|
||||
if(row < 0 || row >= screen->rows)
|
||||
return NULL;
|
||||
if(col < 0 || col >= screen->cols)
|
||||
return NULL;
|
||||
return screen->buffer + (screen->cols * row) + col;
|
||||
}
|
||||
|
||||
static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols)
|
||||
{
|
||||
ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols);
|
||||
int row, col;
|
||||
|
||||
for(row = 0; row < new_rows; row++) {
|
||||
for(col = 0; col < new_cols; col++) {
|
||||
for(int row = 0; row < new_rows; row++) {
|
||||
for(int col = 0; col < new_cols; col++) {
|
||||
ScreenCell *new_cell = new_buffer + row*new_cols + col;
|
||||
|
||||
if(buffer && row < screen->rows && col < screen->cols)
|
||||
@@ -156,49 +169,77 @@ static void damagescreen(VTermScreen *screen)
|
||||
damagerect(screen, rect);
|
||||
}
|
||||
|
||||
static int putglyph(const uint32_t chars[], int width, VTermPos pos, void *user)
|
||||
static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
|
||||
{
|
||||
VTermScreen *screen = user;
|
||||
ScreenCell *cell = getcell(screen, pos.row, pos.col);
|
||||
|
||||
if(!cell)
|
||||
return 0;
|
||||
|
||||
int i;
|
||||
int col;
|
||||
|
||||
VTermRect rect = {
|
||||
.start_row = pos.row,
|
||||
.end_row = pos.row+1,
|
||||
.start_col = pos.col,
|
||||
.end_col = pos.col+width,
|
||||
};
|
||||
|
||||
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && chars[i]; i++) {
|
||||
cell->chars[i] = chars[i];
|
||||
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
|
||||
cell->chars[i] = info->chars[i];
|
||||
cell->pen = screen->pen;
|
||||
}
|
||||
if(i < VTERM_MAX_CHARS_PER_CELL)
|
||||
cell->chars[i] = 0;
|
||||
|
||||
for(col = 1; col < width; col++)
|
||||
for(int col = 1; col < info->width; col++)
|
||||
getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1;
|
||||
|
||||
VTermRect rect = {
|
||||
.start_row = pos.row,
|
||||
.end_row = pos.row+1,
|
||||
.start_col = pos.col,
|
||||
.end_col = pos.col+info->width,
|
||||
};
|
||||
|
||||
cell->pen.protected_cell = info->protected_cell;
|
||||
cell->pen.dwl = info->dwl;
|
||||
cell->pen.dhl = info->dhl;
|
||||
|
||||
damagerect(screen, rect);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void copycell(VTermPos dest, VTermPos src, void *user)
|
||||
{
|
||||
VTermScreen *screen = user;
|
||||
ScreenCell *destcell = getcell(screen, dest.row, dest.col);
|
||||
ScreenCell *srccell = getcell(screen, src.row, src.col);
|
||||
|
||||
*destcell = *srccell;
|
||||
}
|
||||
|
||||
static int moverect_internal(VTermRect dest, VTermRect src, void *user)
|
||||
{
|
||||
VTermScreen *screen = user;
|
||||
|
||||
vterm_copy_cells(dest, src, ©cell, screen);
|
||||
if(screen->callbacks && screen->callbacks->sb_pushline &&
|
||||
dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner
|
||||
dest.end_col == screen->cols && // full width
|
||||
screen->buffer == screen->buffers[0]) { // not altscreen
|
||||
VTermPos pos;
|
||||
for(pos.row = 0; pos.row < src.start_row; pos.row++) {
|
||||
for(pos.col = 0; pos.col < screen->cols; pos.col++)
|
||||
vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col);
|
||||
|
||||
(screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata);
|
||||
}
|
||||
}
|
||||
|
||||
int cols = src.end_col - src.start_col;
|
||||
int downward = src.start_row - dest.start_row;
|
||||
|
||||
int init_row, test_row, inc_row;
|
||||
if(downward < 0) {
|
||||
init_row = dest.end_row - 1;
|
||||
test_row = dest.start_row - 1;
|
||||
inc_row = -1;
|
||||
}
|
||||
else {
|
||||
init_row = dest.start_row;
|
||||
test_row = dest.end_row;
|
||||
inc_row = +1;
|
||||
}
|
||||
|
||||
for(int row = init_row; row != test_row; row += inc_row)
|
||||
memmove(getcell(screen, row, dest.start_col),
|
||||
getcell(screen, row + downward, src.start_col),
|
||||
cols * sizeof(ScreenCell));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -221,22 +262,30 @@ static int moverect_user(VTermRect dest, VTermRect src, void *user)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int erase_internal(VTermRect rect, void *user)
|
||||
static int erase_internal(VTermRect rect, int selective, void *user)
|
||||
{
|
||||
VTermScreen *screen = user;
|
||||
int row, col;
|
||||
|
||||
for(row = rect.start_row; row < rect.end_row; row++)
|
||||
for(col = rect.start_col; col < rect.end_col; col++) {
|
||||
for(int row = rect.start_row; row < rect.end_row; row++) {
|
||||
const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row);
|
||||
|
||||
for(int col = rect.start_col; col < rect.end_col; col++) {
|
||||
ScreenCell *cell = getcell(screen, row, col);
|
||||
|
||||
if(selective && cell->pen.protected_cell)
|
||||
continue;
|
||||
|
||||
cell->chars[0] = 0;
|
||||
cell->pen = screen->pen;
|
||||
cell->pen.dwl = info->doublewidth;
|
||||
cell->pen.dhl = info->doubleheight;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int erase_user(VTermRect rect, void *user)
|
||||
static int erase_user(VTermRect rect, int selective, void *user)
|
||||
{
|
||||
VTermScreen *screen = user;
|
||||
|
||||
@@ -245,10 +294,10 @@ static int erase_user(VTermRect rect, void *user)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int erase(VTermRect rect, void *user)
|
||||
static int erase(VTermRect rect, int selective, void *user)
|
||||
{
|
||||
erase_internal(rect, user);
|
||||
return erase_user(rect, user);
|
||||
erase_internal(rect, selective, user);
|
||||
return erase_user(rect, 0, user);
|
||||
}
|
||||
|
||||
static int scrollrect(VTermRect rect, int downward, int rightward, void *user)
|
||||
@@ -258,48 +307,75 @@ static int scrollrect(VTermRect rect, int downward, int rightward, void *user)
|
||||
vterm_scroll_rect(rect, downward, rightward,
|
||||
moverect_internal, erase_internal, screen);
|
||||
|
||||
if(screen->damage_merge == VTERM_DAMAGE_SCROLL) {
|
||||
if(screen->damaged.start_row != -1 &&
|
||||
!rect_intersects(&rect, &screen->damaged)) {
|
||||
vterm_screen_flush_damage(screen);
|
||||
}
|
||||
if(screen->damage_merge != VTERM_DAMAGE_SCROLL) {
|
||||
vterm_screen_flush_damage(screen);
|
||||
|
||||
if(screen->pending_scrollrect.start_row == -1) {
|
||||
screen->pending_scrollrect = rect;
|
||||
screen->pending_scroll_downward = downward;
|
||||
screen->pending_scroll_rightward = rightward;
|
||||
}
|
||||
else if(rect_equal(&screen->pending_scrollrect, &rect) &&
|
||||
((screen->pending_scroll_downward == 0 && downward == 0) ||
|
||||
(screen->pending_scroll_rightward == 0 && rightward == 0))) {
|
||||
screen->pending_scroll_downward += downward;
|
||||
screen->pending_scroll_rightward += rightward;
|
||||
}
|
||||
else {
|
||||
vterm_screen_flush_damage(screen);
|
||||
|
||||
screen->pending_scrollrect = rect;
|
||||
screen->pending_scroll_downward = downward;
|
||||
screen->pending_scroll_rightward = rightward;
|
||||
}
|
||||
|
||||
if(screen->damaged.start_row != -1) {
|
||||
if(rect_contains(&rect, &screen->damaged)) {
|
||||
vterm_rect_move(&screen->damaged, -downward, -rightward);
|
||||
rect_clip(&screen->damaged, &rect);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "TODO: scrollrect split damage\n");
|
||||
}
|
||||
}
|
||||
vterm_scroll_rect(rect, downward, rightward,
|
||||
moverect_user, erase_user, screen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
vterm_screen_flush_damage(screen);
|
||||
if(screen->damaged.start_row != -1 &&
|
||||
!rect_intersects(&rect, &screen->damaged)) {
|
||||
vterm_screen_flush_damage(screen);
|
||||
}
|
||||
|
||||
vterm_scroll_rect(rect, downward, rightward,
|
||||
moverect_user, erase_user, screen);
|
||||
if(screen->pending_scrollrect.start_row == -1) {
|
||||
screen->pending_scrollrect = rect;
|
||||
screen->pending_scroll_downward = downward;
|
||||
screen->pending_scroll_rightward = rightward;
|
||||
}
|
||||
else if(rect_equal(&screen->pending_scrollrect, &rect) &&
|
||||
((screen->pending_scroll_downward == 0 && downward == 0) ||
|
||||
(screen->pending_scroll_rightward == 0 && rightward == 0))) {
|
||||
screen->pending_scroll_downward += downward;
|
||||
screen->pending_scroll_rightward += rightward;
|
||||
}
|
||||
else {
|
||||
vterm_screen_flush_damage(screen);
|
||||
|
||||
screen->pending_scrollrect = rect;
|
||||
screen->pending_scroll_downward = downward;
|
||||
screen->pending_scroll_rightward = rightward;
|
||||
}
|
||||
|
||||
if(screen->damaged.start_row == -1)
|
||||
return 1;
|
||||
|
||||
if(rect_contains(&rect, &screen->damaged)) {
|
||||
vterm_rect_move(&screen->damaged, -downward, -rightward);
|
||||
rect_clip(&screen->damaged, &rect);
|
||||
}
|
||||
/* There are a number of possible cases here, but lets restrict this to only
|
||||
* the common case where we might actually gain some performance by
|
||||
* optimising it. Namely, a vertical scroll that neatly cuts the damage
|
||||
* region in half.
|
||||
*/
|
||||
else if(rect.start_col <= screen->damaged.start_col &&
|
||||
rect.end_col >= screen->damaged.end_col &&
|
||||
rightward == 0) {
|
||||
if(screen->damaged.start_row >= rect.start_row &&
|
||||
screen->damaged.start_row < rect.end_row) {
|
||||
screen->damaged.start_row -= downward;
|
||||
if(screen->damaged.start_row < rect.start_row)
|
||||
screen->damaged.start_row = rect.start_row;
|
||||
if(screen->damaged.start_row > rect.end_row)
|
||||
screen->damaged.start_row = rect.end_row;
|
||||
}
|
||||
if(screen->damaged.end_row >= rect.start_row &&
|
||||
screen->damaged.end_row < rect.end_row) {
|
||||
screen->damaged.end_row -= downward;
|
||||
if(screen->damaged.end_row < rect.start_row)
|
||||
screen->damaged.end_row = rect.start_row;
|
||||
if(screen->damaged.end_row > rect.end_row)
|
||||
screen->damaged.end_row = rect.end_row;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n",
|
||||
ARGSrect(screen->damaged), ARGSrect(rect));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -401,25 +477,52 @@ static int bell(void *user)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resize(int new_rows, int new_cols, void *user)
|
||||
static int resize(int new_rows, int new_cols, VTermPos *delta, void *user)
|
||||
{
|
||||
VTermScreen *screen = user;
|
||||
int old_rows, old_cols;
|
||||
|
||||
int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]);
|
||||
|
||||
int old_rows = screen->rows;
|
||||
int old_cols = screen->cols;
|
||||
|
||||
if(!is_altscreen && new_rows < old_rows) {
|
||||
// Fewer rows - determine if we're going to scroll at all, and if so, push
|
||||
// those lines to scrollback
|
||||
VTermPos pos = { 0, 0 };
|
||||
for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--)
|
||||
if(!vterm_screen_is_eol(screen, pos))
|
||||
break;
|
||||
|
||||
int first_blank_row = pos.row + 1;
|
||||
if(first_blank_row > new_rows) {
|
||||
VTermRect rect = {
|
||||
.start_row = 0,
|
||||
.end_row = old_rows,
|
||||
.start_col = 0,
|
||||
.end_col = old_cols,
|
||||
};
|
||||
scrollrect(rect, first_blank_row - new_rows, 0, user);
|
||||
vterm_screen_flush_damage(screen);
|
||||
|
||||
delta->row -= first_blank_row - new_rows;
|
||||
}
|
||||
}
|
||||
|
||||
screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols);
|
||||
if(screen->buffers[1])
|
||||
screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols);
|
||||
|
||||
screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0];
|
||||
|
||||
old_rows = screen->rows;
|
||||
old_cols = screen->cols;
|
||||
|
||||
screen->rows = new_rows;
|
||||
screen->cols = new_cols;
|
||||
|
||||
if(screen->sb_buffer)
|
||||
vterm_allocator_free(screen->vt, screen->sb_buffer);
|
||||
|
||||
screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols);
|
||||
|
||||
if(new_cols > old_cols) {
|
||||
VTermRect rect = {
|
||||
.start_row = 0,
|
||||
@@ -431,6 +534,34 @@ static int resize(int new_rows, int new_cols, void *user)
|
||||
}
|
||||
|
||||
if(new_rows > old_rows) {
|
||||
if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) {
|
||||
int rows = new_rows - old_rows;
|
||||
while(rows) {
|
||||
if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata)))
|
||||
break;
|
||||
|
||||
VTermRect rect = {
|
||||
.start_row = 0,
|
||||
.end_row = screen->rows,
|
||||
.start_col = 0,
|
||||
.end_col = screen->cols,
|
||||
};
|
||||
scrollrect(rect, -1, 0, user);
|
||||
|
||||
VTermPos pos = { 0, 0 };
|
||||
for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width)
|
||||
vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col);
|
||||
|
||||
rect.end_row = 1;
|
||||
damagerect(screen, rect);
|
||||
|
||||
vterm_screen_flush_damage(screen);
|
||||
|
||||
rows--;
|
||||
delta->row++;
|
||||
}
|
||||
}
|
||||
|
||||
VTermRect rect = {
|
||||
.start_row = old_rows,
|
||||
.end_row = new_rows,
|
||||
@@ -446,6 +577,37 @@ static int resize(int new_rows, int new_cols, void *user)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user)
|
||||
{
|
||||
VTermScreen *screen = user;
|
||||
|
||||
if(newinfo->doublewidth != oldinfo->doublewidth ||
|
||||
newinfo->doubleheight != oldinfo->doubleheight) {
|
||||
for(int col = 0; col < screen->cols; col++) {
|
||||
ScreenCell *cell = getcell(screen, row, col);
|
||||
cell->pen.dwl = newinfo->doublewidth;
|
||||
cell->pen.dhl = newinfo->doubleheight;
|
||||
}
|
||||
|
||||
VTermRect rect = {
|
||||
.start_row = row,
|
||||
.end_row = row + 1,
|
||||
.start_col = 0,
|
||||
.end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols,
|
||||
};
|
||||
damagerect(screen, rect);
|
||||
|
||||
if(newinfo->doublewidth) {
|
||||
rect.start_col = screen->cols / 2;
|
||||
rect.end_col = screen->cols;
|
||||
|
||||
erase_internal(rect, 0, user);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static VTermStateCallbacks state_cbs = {
|
||||
.putglyph = &putglyph,
|
||||
.movecursor = &movecursor,
|
||||
@@ -456,18 +618,17 @@ static VTermStateCallbacks state_cbs = {
|
||||
.setmousefunc = &setmousefunc,
|
||||
.bell = &bell,
|
||||
.resize = &resize,
|
||||
.setlineinfo = &setlineinfo,
|
||||
};
|
||||
|
||||
static VTermScreen *screen_new(VTerm *vt)
|
||||
{
|
||||
VTermState *state = vterm_obtain_state(vt);
|
||||
VTermScreen *screen;
|
||||
int rows, cols;
|
||||
|
||||
if(!state)
|
||||
return NULL;
|
||||
|
||||
screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));
|
||||
VTermScreen *screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));
|
||||
int rows, cols;
|
||||
|
||||
vterm_get_size(vt, &rows, &cols);
|
||||
|
||||
@@ -485,17 +646,21 @@ static VTermScreen *screen_new(VTerm *vt)
|
||||
|
||||
screen->buffer = screen->buffers[0];
|
||||
|
||||
screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols);
|
||||
|
||||
vterm_state_set_callbacks(screen->state, &state_cbs, screen);
|
||||
|
||||
return screen;
|
||||
}
|
||||
|
||||
void vterm_screen_free(VTermScreen *screen)
|
||||
INTERNAL void vterm_screen_free(VTermScreen *screen)
|
||||
{
|
||||
vterm_allocator_free(screen->vt, screen->buffers[0]);
|
||||
if(screen->buffers[1])
|
||||
vterm_allocator_free(screen->vt, screen->buffers[1]);
|
||||
|
||||
vterm_allocator_free(screen->vt, screen->sb_buffer);
|
||||
|
||||
vterm_allocator_free(screen->vt, screen);
|
||||
}
|
||||
|
||||
@@ -507,12 +672,10 @@ void vterm_screen_reset(VTermScreen *screen, int hard)
|
||||
vterm_screen_flush_damage(screen);
|
||||
}
|
||||
|
||||
static size_t _get_chars(VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect)
|
||||
static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect)
|
||||
{
|
||||
size_t outpos = 0;
|
||||
int padding = 0;
|
||||
int row, col;
|
||||
int i;
|
||||
|
||||
#define PUT(c) \
|
||||
if(utf8) { \
|
||||
@@ -529,8 +692,8 @@ static size_t _get_chars(VTermScreen *screen, const int utf8, void *buffer, size
|
||||
outpos++; \
|
||||
}
|
||||
|
||||
for(row = rect.start_row; row < rect.end_row; row++) {
|
||||
for(col = rect.start_col; col < rect.end_col; col++) {
|
||||
for(int row = rect.start_row; row < rect.end_row; row++) {
|
||||
for(int col = rect.start_col; col < rect.end_col; col++) {
|
||||
ScreenCell *cell = getcell(screen, row, col);
|
||||
|
||||
if(cell->chars[0] == 0)
|
||||
@@ -544,7 +707,7 @@ static size_t _get_chars(VTermScreen *screen, const int utf8, void *buffer, size
|
||||
PUT(UNICODE_SPACE);
|
||||
padding--;
|
||||
}
|
||||
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
|
||||
for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
|
||||
PUT(cell->chars[i]);
|
||||
}
|
||||
}
|
||||
@@ -559,23 +722,24 @@ static size_t _get_chars(VTermScreen *screen, const int utf8, void *buffer, size
|
||||
return outpos;
|
||||
}
|
||||
|
||||
size_t vterm_screen_get_chars(VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect)
|
||||
size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect)
|
||||
{
|
||||
return _get_chars(screen, 0, chars, len, rect);
|
||||
}
|
||||
|
||||
size_t vterm_screen_get_text(VTermScreen *screen, char *str, size_t len, const VTermRect rect)
|
||||
size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect)
|
||||
{
|
||||
return _get_chars(screen, 1, str, len, rect);
|
||||
}
|
||||
|
||||
/* Copy internal to external representation of a screen cell */
|
||||
void vterm_screen_get_cell(VTermScreen *screen, VTermPos pos, VTermScreenCell *cell)
|
||||
int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell)
|
||||
{
|
||||
ScreenCell *intcell = getcell(screen, pos.row, pos.col);
|
||||
int i;
|
||||
if(!intcell)
|
||||
return 0;
|
||||
|
||||
for(i = 0; ; i++) {
|
||||
for(int i = 0; ; i++) {
|
||||
cell->chars[i] = intcell->chars[i];
|
||||
if(!intcell->chars[i])
|
||||
break;
|
||||
@@ -589,6 +753,9 @@ void vterm_screen_get_cell(VTermScreen *screen, VTermPos pos, VTermScreenCell *c
|
||||
cell->attrs.strike = intcell->pen.strike;
|
||||
cell->attrs.font = intcell->pen.font;
|
||||
|
||||
cell->attrs.dwl = intcell->pen.dwl;
|
||||
cell->attrs.dhl = intcell->pen.dhl;
|
||||
|
||||
cell->fg = intcell->pen.fg;
|
||||
cell->bg = intcell->pen.bg;
|
||||
|
||||
@@ -597,9 +764,42 @@ void vterm_screen_get_cell(VTermScreen *screen, VTermPos pos, VTermScreenCell *c
|
||||
cell->width = 2;
|
||||
else
|
||||
cell->width = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vterm_screen_is_eol(VTermScreen *screen, VTermPos pos)
|
||||
/* Copy external to internal representation of a screen cell */
|
||||
/* static because it's only used internally for sb_popline during resize */
|
||||
static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell)
|
||||
{
|
||||
ScreenCell *intcell = getcell(screen, pos.row, pos.col);
|
||||
if(!intcell)
|
||||
return 0;
|
||||
|
||||
for(int i = 0; ; i++) {
|
||||
intcell->chars[i] = cell->chars[i];
|
||||
if(!cell->chars[i])
|
||||
break;
|
||||
}
|
||||
|
||||
intcell->pen.bold = cell->attrs.bold;
|
||||
intcell->pen.underline = cell->attrs.underline;
|
||||
intcell->pen.italic = cell->attrs.italic;
|
||||
intcell->pen.blink = cell->attrs.blink;
|
||||
intcell->pen.reverse = cell->attrs.reverse ^ screen->global_reverse;
|
||||
intcell->pen.strike = cell->attrs.strike;
|
||||
intcell->pen.font = cell->attrs.font;
|
||||
|
||||
intcell->pen.fg = cell->fg;
|
||||
intcell->pen.bg = cell->bg;
|
||||
|
||||
if(cell->width == 2)
|
||||
getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos)
|
||||
{
|
||||
/* This cell is EOL if this and every cell to the right is black */
|
||||
for(; pos.col < screen->cols; pos.col++) {
|
||||
@@ -613,11 +813,10 @@ int vterm_screen_is_eol(VTermScreen *screen, VTermPos pos)
|
||||
|
||||
VTermScreen *vterm_obtain_screen(VTerm *vt)
|
||||
{
|
||||
VTermScreen *screen;
|
||||
if(vt->screen)
|
||||
return vt->screen;
|
||||
|
||||
screen = screen_new(vt);
|
||||
VTermScreen *screen = screen_new(vt);
|
||||
vt->screen = screen;
|
||||
|
||||
return screen;
|
||||
@@ -662,3 +861,55 @@ void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size)
|
||||
vterm_screen_flush_damage(screen);
|
||||
screen->damage_merge = size;
|
||||
}
|
||||
|
||||
static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b)
|
||||
{
|
||||
if((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold))
|
||||
return 1;
|
||||
if((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline))
|
||||
return 1;
|
||||
if((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic))
|
||||
return 1;
|
||||
if((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink))
|
||||
return 1;
|
||||
if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse))
|
||||
return 1;
|
||||
if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike))
|
||||
return 1;
|
||||
if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font))
|
||||
return 1;
|
||||
if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_equal(a->pen.fg, b->pen.fg))
|
||||
return 1;
|
||||
if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs)
|
||||
{
|
||||
ScreenCell *target = getcell(screen, pos.row, pos.col);
|
||||
|
||||
// TODO: bounds check
|
||||
extent->start_row = pos.row;
|
||||
extent->end_row = pos.row + 1;
|
||||
|
||||
if(extent->start_col < 0)
|
||||
extent->start_col = 0;
|
||||
if(extent->end_col < 0)
|
||||
extent->end_col = screen->cols;
|
||||
|
||||
int col;
|
||||
|
||||
for(col = pos.col - 1; col >= extent->start_col; col--)
|
||||
if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
|
||||
break;
|
||||
extent->start_col = col + 1;
|
||||
|
||||
for(col = pos.col + 1; col < extent->end_col; col++)
|
||||
if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
|
||||
break;
|
||||
extent->end_col = col - 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -213,7 +213,7 @@ static int mk_wcwidth(wchar_t ucs)
|
||||
(ucs >= 0x30000 && ucs <= 0x3fffd)));
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
static int mk_wcswidth(const wchar_t *pwcs, size_t n)
|
||||
{
|
||||
int w, width = 0;
|
||||
@@ -227,6 +227,7 @@ static int mk_wcswidth(const wchar_t *pwcs, size_t n)
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The following functions are the same as mk_wcwidth() and
|
||||
* mk_wcswidth(), except that spacing characters in the East Asian
|
||||
@@ -316,17 +317,16 @@ static int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
|
||||
|
||||
return width;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ################################
|
||||
// ### The rest added by Paul Evans
|
||||
|
||||
int vterm_unicode_width(int codepoint)
|
||||
INTERNAL int vterm_unicode_width(int codepoint)
|
||||
{
|
||||
return mk_wcwidth(codepoint);
|
||||
}
|
||||
|
||||
int vterm_unicode_is_combining(int codepoint)
|
||||
INTERNAL int vterm_unicode_is_combining(int codepoint)
|
||||
{
|
||||
return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1);
|
||||
}
|
||||
|
||||
@@ -12,15 +12,13 @@ static inline unsigned int utf8_seqlen(long codepoint)
|
||||
return 6;
|
||||
}
|
||||
|
||||
/* Does NOT NUL-terminate the buffer */
|
||||
static int fill_utf8(long codepoint, char *str)
|
||||
{
|
||||
int b;
|
||||
int nbytes = utf8_seqlen(codepoint);
|
||||
|
||||
str[nbytes] = 0;
|
||||
|
||||
// This is easier done backwards
|
||||
b = nbytes;
|
||||
int b = nbytes;
|
||||
while(b > 1) {
|
||||
b--;
|
||||
str[b] = 0x80 | (codepoint & 0x3f);
|
||||
|
||||
@@ -70,17 +70,17 @@ void vterm_free(VTerm *vt)
|
||||
vterm_allocator_free(vt, vt);
|
||||
}
|
||||
|
||||
void *vterm_allocator_malloc(VTerm *vt, size_t size)
|
||||
INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
|
||||
{
|
||||
return (*vt->allocator->malloc)(size, vt->allocdata);
|
||||
}
|
||||
|
||||
void vterm_allocator_free(VTerm *vt, void *ptr)
|
||||
INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
|
||||
{
|
||||
(*vt->allocator->free)(ptr, vt->allocdata);
|
||||
}
|
||||
|
||||
void vterm_get_size(VTerm *vt, int *rowsp, int *colsp)
|
||||
void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
|
||||
{
|
||||
if(rowsp)
|
||||
*rowsp = vt->rows;
|
||||
@@ -105,10 +105,10 @@ void vterm_set_parser_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks
|
||||
|
||||
void vterm_parser_set_utf8(VTerm *vt, int is_utf8)
|
||||
{
|
||||
vt->is_utf8 = is_utf8;
|
||||
vt->mode.utf8 = is_utf8;
|
||||
}
|
||||
|
||||
void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
|
||||
INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
|
||||
{
|
||||
if(len > vt->outbuffer_len - vt->outbuffer_cur) {
|
||||
fprintf(stderr, "vterm_push_output(): buffer overflow; truncating output\n");
|
||||
@@ -119,7 +119,7 @@ void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
|
||||
vt->outbuffer_cur += len;
|
||||
}
|
||||
|
||||
void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
|
||||
INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
|
||||
{
|
||||
int written = vsnprintf(vt->outbuffer + vt->outbuffer_cur,
|
||||
vt->outbuffer_len - vt->outbuffer_cur,
|
||||
@@ -127,7 +127,7 @@ void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
|
||||
vt->outbuffer_cur += written;
|
||||
}
|
||||
|
||||
void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
|
||||
INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
@@ -135,22 +135,50 @@ void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
|
||||
{
|
||||
if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
|
||||
vterm_push_output_sprintf(vt, "\e%c", ctrl - 0x40);
|
||||
else
|
||||
vterm_push_output_sprintf(vt, "%c", ctrl);
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vterm_push_output_vsprintf(vt, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
|
||||
{
|
||||
if(!vt->mode.ctrl8bit)
|
||||
vterm_push_output_sprintf(vt, "\e%c", C1_DCS - 0x40);
|
||||
else
|
||||
vterm_push_output_sprintf(vt, "%c", C1_DCS);
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vterm_push_output_vsprintf(vt, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
vterm_push_output_sprintf_ctrl(vt, C1_ST, "");
|
||||
}
|
||||
|
||||
size_t vterm_output_bufferlen(VTerm *vt)
|
||||
{
|
||||
return vterm_output_get_buffer_current(vt);
|
||||
}
|
||||
|
||||
size_t vterm_output_get_buffer_size(VTerm *vt)
|
||||
size_t vterm_output_get_buffer_size(const VTerm *vt)
|
||||
{
|
||||
return vt->outbuffer_len;
|
||||
}
|
||||
|
||||
size_t vterm_output_get_buffer_current(VTerm *vt)
|
||||
size_t vterm_output_get_buffer_current(const VTerm *vt)
|
||||
{
|
||||
return vt->outbuffer_cur;
|
||||
}
|
||||
|
||||
size_t vterm_output_get_buffer_remaining(VTerm *vt)
|
||||
size_t vterm_output_get_buffer_remaining(const VTerm *vt)
|
||||
{
|
||||
return vt->outbuffer_len - vt->outbuffer_cur;
|
||||
}
|
||||
@@ -204,7 +232,7 @@ void vterm_scroll_rect(VTermRect rect,
|
||||
int downward,
|
||||
int rightward,
|
||||
int (*moverect)(VTermRect src, VTermRect dest, void *user),
|
||||
int (*eraserect)(VTermRect rect, void *user),
|
||||
int (*eraserect)(VTermRect rect, int selective, void *user),
|
||||
void *user)
|
||||
{
|
||||
VTermRect src;
|
||||
@@ -213,7 +241,7 @@ void vterm_scroll_rect(VTermRect rect,
|
||||
if(abs(downward) >= rect.end_row - rect.start_row ||
|
||||
abs(rightward) >= rect.end_col - rect.start_col) {
|
||||
/* Scroll more than area; just erase the lot */
|
||||
(*eraserect)(rect, user);
|
||||
(*eraserect)(rect, 0, user);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -266,7 +294,7 @@ void vterm_scroll_rect(VTermRect rect,
|
||||
else if(rightward < 0)
|
||||
rect.end_col = rect.start_col - rightward;
|
||||
|
||||
(*eraserect)(rect, user);
|
||||
(*eraserect)(rect, 0, user);
|
||||
}
|
||||
|
||||
void vterm_copy_cells(VTermRect dest,
|
||||
@@ -280,19 +308,12 @@ void vterm_copy_cells(VTermRect dest,
|
||||
int init_row, test_row, init_col, test_col;
|
||||
int inc_row, inc_col;
|
||||
|
||||
VTermPos pos;
|
||||
|
||||
if(downward < 0) {
|
||||
init_row = dest.end_row - 1;
|
||||
test_row = dest.start_row - 1;
|
||||
inc_row = -1;
|
||||
}
|
||||
else if(downward == 0) {
|
||||
init_row = dest.start_row;
|
||||
test_row = dest.end_row;
|
||||
inc_row = +1;
|
||||
}
|
||||
else /* downward > 0 */ {
|
||||
else /* downward >= 0 */ {
|
||||
init_row = dest.start_row;
|
||||
test_row = dest.end_row;
|
||||
inc_row = +1;
|
||||
@@ -303,17 +324,13 @@ void vterm_copy_cells(VTermRect dest,
|
||||
test_col = dest.start_col - 1;
|
||||
inc_col = -1;
|
||||
}
|
||||
else if(rightward == 0) {
|
||||
init_col = dest.start_col;
|
||||
test_col = dest.end_col;
|
||||
inc_col = +1;
|
||||
}
|
||||
else /* rightward > 0 */ {
|
||||
else /* rightward >= 0 */ {
|
||||
init_col = dest.start_col;
|
||||
test_col = dest.end_col;
|
||||
inc_col = +1;
|
||||
}
|
||||
|
||||
VTermPos pos;
|
||||
for(pos.row = init_row; pos.row != test_row; pos.row += inc_row)
|
||||
for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) {
|
||||
VTermPos srcpos = { pos.row + downward, pos.col + rightward };
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define INTERNAL __attribute__((visibility("internal")))
|
||||
#else
|
||||
# define INTERNAL
|
||||
#endif
|
||||
|
||||
typedef struct VTermEncoding VTermEncoding;
|
||||
|
||||
typedef struct {
|
||||
@@ -27,6 +33,11 @@ struct VTermPen
|
||||
unsigned int font:4; /* To store 0-9 */
|
||||
};
|
||||
|
||||
static inline int vterm_color_equal(VTermColor a, VTermColor b)
|
||||
{
|
||||
return a.red == b.red && a.green == b.green && a.blue == b.blue;
|
||||
}
|
||||
|
||||
struct VTermState
|
||||
{
|
||||
VTerm *vt;
|
||||
@@ -42,13 +53,21 @@ struct VTermState
|
||||
|
||||
int at_phantom; /* True if we're on the "81st" phantom column to defer a wraparound */
|
||||
|
||||
int scrollregion_start;
|
||||
int scrollregion_end; /* -1 means unbounded */
|
||||
#define SCROLLREGION_END(state) ((state)->scrollregion_end > -1 ? (state)->scrollregion_end : (state)->rows)
|
||||
int scrollregion_top;
|
||||
int scrollregion_bottom; /* -1 means unbounded */
|
||||
#define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows)
|
||||
int scrollregion_left;
|
||||
#define SCROLLREGION_LEFT(state) ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0)
|
||||
int scrollregion_right; /* -1 means unbounded */
|
||||
#define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols)
|
||||
|
||||
/* Bitvector of tab stops */
|
||||
unsigned char *tabstops;
|
||||
|
||||
VTermLineInfo *lineinfo;
|
||||
#define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols)
|
||||
#define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row)
|
||||
|
||||
/* Mouse state */
|
||||
int mouse_col, mouse_row;
|
||||
int mouse_buttons;
|
||||
@@ -72,18 +91,25 @@ struct VTermState
|
||||
unsigned int cursor_shape:2;
|
||||
int alt_screen:1;
|
||||
int origin:1;
|
||||
int screen:1;
|
||||
int leftrightmargin:1;
|
||||
} mode;
|
||||
|
||||
VTermEncodingInstance encoding[4], encoding_utf8;
|
||||
int gl_set, gr_set;
|
||||
int gl_set, gr_set, gsingle_set;
|
||||
|
||||
struct VTermPen pen;
|
||||
|
||||
VTermColor default_fg;
|
||||
VTermColor default_bg;
|
||||
int fg_ansi;
|
||||
VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only
|
||||
|
||||
int fg_index;
|
||||
int bg_index;
|
||||
int bold_is_highbright;
|
||||
|
||||
unsigned int protected_cell : 1;
|
||||
|
||||
/* Saved state under DEC mode 1048/1049 */
|
||||
struct {
|
||||
VTermPos pos;
|
||||
@@ -105,7 +131,10 @@ struct VTerm
|
||||
int rows;
|
||||
int cols;
|
||||
|
||||
int is_utf8;
|
||||
struct {
|
||||
int utf8:1;
|
||||
int ctrl8bit:1;
|
||||
} mode;
|
||||
|
||||
enum VTermParserState {
|
||||
NORMAL,
|
||||
@@ -150,13 +179,26 @@ void vterm_allocator_free(VTerm *vt, void *ptr);
|
||||
void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len);
|
||||
void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args);
|
||||
void vterm_push_output_sprintf(VTerm *vt, const char *format, ...);
|
||||
void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...);
|
||||
void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...);
|
||||
|
||||
void vterm_state_free(VTermState *state);
|
||||
|
||||
void vterm_state_newpen(VTermState *state);
|
||||
void vterm_state_resetpen(VTermState *state);
|
||||
void vterm_state_setpen(VTermState *state, const long args[], int argcount);
|
||||
int vterm_state_getpen(VTermState *state, long args[], int argcount);
|
||||
void vterm_state_savepen(VTermState *state, int save);
|
||||
|
||||
enum {
|
||||
C1_SS3 = 0x8f,
|
||||
C1_DCS = 0x90,
|
||||
C1_CSI = 0x9b,
|
||||
C1_ST = 0x9c,
|
||||
};
|
||||
|
||||
void vterm_state_push_output_sprintf_CSI(VTermState *vts, const char *format, ...);
|
||||
|
||||
void vterm_screen_free(VTermScreen *screen);
|
||||
|
||||
VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation);
|
||||
|
||||
Reference in New Issue
Block a user