summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2014-12-04 19:52:44 -0800
committerElliott Hughes <enh@google.com>2014-12-08 10:20:27 -0800
commit6d78f36633063dad0689ca42be1ad8d0313ebfab (patch)
treeceb6f00eed769828f816834ebb7899551a9a15bd
parent73fbfc38792bd96137d5b6ae3016dfc4d9805d46 (diff)
downloadandroid_external_libvterm-stable/cm-12.0-YNG1T.tar.gz
android_external_libvterm-stable/cm-12.0-YNG1T.tar.bz2
android_external_libvterm-stable/cm-12.0-YNG1T.zip
Change-Id: I9a734b40a172d9c13be4fdf38db60c6916d7d8d0
-rw-r--r--Android.mk8
-rw-r--r--include/vterm.h14
-rw-r--r--src/encoding.c3
-rw-r--r--src/input.c11
-rw-r--r--src/pen.c44
-rw-r--r--src/screen.c48
-rw-r--r--src/state.c168
-rw-r--r--src/unicode.c4
-rw-r--r--src/utf8.h3
-rw-r--r--src/vterm.c14
-rw-r--r--src/vterm_internal.h13
11 files changed, 274 insertions, 56 deletions
diff --git a/Android.mk b/Android.mk
index 4eeca87..dac5231 100644
--- a/Android.mk
+++ b/Android.mk
@@ -18,6 +18,12 @@ LOCAL_SRC_FILES := \
src/screen.c \
src/state.c
-LOCAL_CFLAGS := -std=c99
+LOCAL_CFLAGS += \
+ -std=c99 \
+ -Wno-missing-field-initializers \
+ -Wno-sign-compare \
+ -Wno-unused-parameter \
+
+LOCAL_CLANG := true
include $(BUILD_STATIC_LIBRARY)
diff --git a/include/vterm.h b/include/vterm.h
index 2e2b32b..d43add7 100644
--- a/include/vterm.h
+++ b/include/vterm.h
@@ -103,9 +103,16 @@ typedef struct {
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 {
+ 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
* by the allocator. */
void *(*malloc)(size_t size, void *allocdata);
@@ -187,6 +194,7 @@ typedef struct {
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);
@@ -197,9 +205,11 @@ 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(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);
// ------------
// Screen layer
@@ -217,6 +227,8 @@ typedef struct {
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;
@@ -249,6 +261,8 @@ 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);
+
+/* 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);
diff --git a/src/encoding.c b/src/encoding.c
index a7629f9..1495855 100644
--- a/src/encoding.c
+++ b/src/encoding.c
@@ -2,7 +2,7 @@
#define UNICODE_INVALID 0xFFFD
-#ifdef DEBUG
+#if defined(DEBUG) && DEBUG > 1
# define DEBUG_PRINT_UTF8
#endif
@@ -212,6 +212,7 @@ encodings[] = {
{ 0 },
};
+/* This ought to be INTERNAL but isn't because it's used by unit testing */
VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation)
{
for(int i = 0; encodings[i].designation; i++)
diff --git a/src/input.c b/src/input.c
index 36bec56..0eaf0e9 100644
--- a/src/input.c
+++ b/src/input.c
@@ -11,11 +11,6 @@ void vterm_input_push_char(VTerm *vt, VTermModifier mod, uint32_t c)
*/
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
@@ -128,12 +123,6 @@ static keycodes_s keycodes_kp[] = {
void vterm_input_push_key(VTerm *vt, VTermModifier mod, VTermKey key)
{
- /* 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)
return;
diff --git a/src/pen.c b/src/pen.c
index 044e9aa..fb8c8e3 100644
--- a/src/pen.c
+++ b/src/pen.c
@@ -33,18 +33,18 @@ static int ramp24[] = {
0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF,
};
-static void lookup_colour_ansi(long index, 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 void lookup_colour_palette(long index, VTermColor *col)
+static void lookup_colour_palette(const VTermState *state, long index, VTermColor *col)
{
if(index >= 0 && index < 16) {
// Normal 8 colours or high intensity - parse as palette 0
- lookup_colour_ansi(index, col);
+ lookup_colour_ansi(state, index, col);
}
else if(index >= 16 && index < 232) {
// 216-colour cube
@@ -64,7 +64,7 @@ static void lookup_colour_palette(long index, VTermColor *col)
}
}
-static int lookup_colour(int palette, const long args[], int argcount, VTermColor *col, int *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
@@ -81,7 +81,7 @@ static int lookup_colour(int palette, const long args[], int argcount, VTermColo
if(index)
*index = CSI_ARG_OR(args[0], -1);
- lookup_colour_palette(argcount ? CSI_ARG_OR(args[0], -1) : -1, col);
+ lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col);
return argcount ? 1 : 0;
@@ -128,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, 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);
@@ -149,7 +159,7 @@ void vterm_state_resetpen(VTermState *state)
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;
@@ -177,7 +187,7 @@ void vterm_state_get_default_colors(const VTermState *state, VTermColor *default
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col)
{
- lookup_colour_palette(index, col);
+ lookup_colour_palette(state, index, col);
}
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg)
@@ -186,12 +196,18 @@ void vterm_state_set_default_colors(VTermState *state, const VTermColor *default
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
@@ -296,7 +312,7 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount)
state->fg_index = -1;
if(argcount - argi < 1)
return;
- argi += 1 + lookup_colour(CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index);
+ 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;
@@ -317,7 +333,7 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount)
state->bg_index = -1;
if(argcount - argi < 1)
return;
- argi += 1 + lookup_colour(CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index);
+ 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;
@@ -353,7 +369,7 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount)
}
}
-int vterm_state_getpen(VTermState *state, long args[], int argcount)
+INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount)
{
int argi = 0;
diff --git a/src/screen.c b/src/screen.c
index db11c6d..c4de59e 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -25,6 +25,8 @@ typedef struct
/* 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 */
@@ -194,6 +196,8 @@ static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
};
cell->pen.protected_cell = info->protected_cell;
+ cell->pen.dwl = info->dwl;
+ cell->pen.dhl = info->dhl;
damagerect(screen, rect);
@@ -262,7 +266,9 @@ static int erase_internal(VTermRect rect, int selective, void *user)
{
VTermScreen *screen = user;
- for(int row = rect.start_row; row < rect.end_row; row++)
+ 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);
@@ -271,7 +277,10 @@ static int erase_internal(VTermRect rect, int selective, void *user)
cell->chars[0] = 0;
cell->pen = screen->pen;
+ cell->pen.dwl = info->doublewidth;
+ cell->pen.dhl = info->doubleheight;
}
+ }
return 1;
}
@@ -568,6 +577,37 @@ static int resize(int new_rows, int new_cols, VTermPos *delta, 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,
@@ -578,6 +618,7 @@ static VTermStateCallbacks state_cbs = {
.setmousefunc = &setmousefunc,
.bell = &bell,
.resize = &resize,
+ .setlineinfo = &setlineinfo,
};
static VTermScreen *screen_new(VTerm *vt)
@@ -612,7 +653,7 @@ static VTermScreen *screen_new(VTerm *vt)
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])
@@ -712,6 +753,9 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe
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;
diff --git a/src/state.c b/src/state.c
index f5348c9..e42be53 100644
--- a/src/state.c
+++ b/src/state.c
@@ -7,7 +7,7 @@
#include "utf8.h"
-#ifdef DEBUG
+#if defined(DEBUG) && DEBUG > 1
# define DEBUG_GLYPH_COMBINE
#endif
@@ -23,6 +23,8 @@ static void putglyph(VTermState *state, const uint32_t chars[], int width, VTerm
.chars = chars,
.width = width,
.protected_cell = state->protected_cell,
+ .dwl = state->lineinfo[pos.row].doublewidth,
+ .dhl = state->lineinfo[pos.row].doubleheight,
};
if(state->callbacks && state->callbacks->putglyph)
@@ -61,18 +63,17 @@ static VTermState *vterm_state_new(VTerm *vt)
state->rows = vt->rows;
state->cols = vt->cols;
- // 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;
+ vterm_state_newpen(state);
state->bold_is_highbright = 0;
return state;
}
-void vterm_state_free(VTermState *state)
+INTERNAL void vterm_state_free(VTermState *state)
{
vterm_allocator_free(state->vt, state->tabstops);
+ vterm_allocator_free(state->vt, state->lineinfo);
vterm_allocator_free(state->vt, state->combine_chars);
vterm_allocator_free(state->vt, state);
}
@@ -82,6 +83,20 @@ static void scroll(VTermState *state, VTermRect rect, int downward, int rightwar
if(!downward && !rightward)
return;
+ // Update lineinfo if full line
+ if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) {
+ int height = rect.end_row - rect.start_row - abs(downward);
+
+ if(downward > 0)
+ memmove(state->lineinfo + rect.start_row,
+ state->lineinfo + rect.start_row + downward,
+ height * sizeof(state->lineinfo[0]));
+ else
+ memmove(state->lineinfo + rect.start_row - downward,
+ state->lineinfo + rect.start_row,
+ height * sizeof(state->lineinfo[0]));
+ }
+
if(state->callbacks && state->callbacks->scrollrect)
if((*state->callbacks->scrollrect)(rect, downward, rightward, state->cbdata))
return;
@@ -115,7 +130,9 @@ static void grow_combine_buffer(VTermState *state)
memcpy(new_chars, state->combine_chars, state->combine_chars_size * sizeof(new_chars[0]));
vterm_allocator_free(state->vt, state->combine_chars);
+
state->combine_chars = new_chars;
+ state->combine_chars_size = new_size;
}
static void set_col_tabstop(VTermState *state, int col)
@@ -139,7 +156,7 @@ static int is_col_tabstop(VTermState *state, int col)
static void tab(VTermState *state, int count, int direction)
{
while(count--)
- while(state->pos.col >= 0 && state->pos.col < state->cols-1) {
+ while(state->pos.col >= 0 && state->pos.col < THISROWWIDTH(state)-1) {
state->pos.col += direction;
if(is_col_tabstop(state, state->pos.col))
@@ -147,6 +164,40 @@ static void tab(VTermState *state, int count, int direction)
}
}
+#define NO_FORCE 0
+#define FORCE 1
+
+#define DWL_OFF 0
+#define DWL_ON 1
+
+#define DHL_OFF 0
+#define DHL_TOP 1
+#define DHL_BOTTOM 2
+
+static void set_lineinfo(VTermState *state, int row, int force, int dwl, int dhl)
+{
+ VTermLineInfo info = state->lineinfo[row];
+
+ if(dwl == DWL_OFF)
+ info.doublewidth = DWL_OFF;
+ else if(dwl == DWL_ON)
+ info.doublewidth = DWL_ON;
+ // else -1 to ignore
+
+ if(dhl == DHL_OFF)
+ info.doubleheight = DHL_OFF;
+ else if(dhl == DHL_TOP)
+ info.doubleheight = DHL_TOP;
+ else if(dhl == DHL_BOTTOM)
+ info.doubleheight = DHL_BOTTOM;
+
+ if((state->callbacks &&
+ state->callbacks->setlineinfo &&
+ (*state->callbacks->setlineinfo)(row, &info, state->lineinfo + row, state->cbdata))
+ || force)
+ state->lineinfo[row] = info;
+}
+
static int on_text(const char bytes[], size_t len, void *user)
{
VTermState *state = user;
@@ -243,7 +294,7 @@ static int on_text(const char bytes[], size_t len, void *user)
printf("}, onscreen width %d\n", width);
#endif
- if(state->at_phantom || state->pos.col + width > state->cols) {
+ if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) {
linefeed(state);
state->pos.col = 0;
state->at_phantom = 0;
@@ -258,10 +309,11 @@ static int on_text(const char bytes[], size_t len, void *user)
.start_row = state->pos.row,
.end_row = state->pos.row + 1,
.start_col = state->pos.col,
- .end_col = state->cols,
+ .end_col = THISROWWIDTH(state),
};
scroll(state, rect, 0, -1);
}
+
putglyph(state, chars, width, state->pos);
if(i == npoints - 1) {
@@ -280,7 +332,7 @@ static int on_text(const char bytes[], size_t len, void *user)
state->combine_pos = state->pos;
}
- if(state->pos.col + width >= state->cols) {
+ if(state->pos.col + width >= THISROWWIDTH(state)) {
if(state->mode.autowrap)
state->at_phantom = 1;
}
@@ -408,6 +460,7 @@ static void output_mouse(VTermState *state, int code, int pressed, int modifiers
len += fill_utf8((code | modifiers) + 0x20, utf8 + len);
len += fill_utf8(col + 0x21, utf8 + len);
len += fill_utf8(row + 0x21, utf8 + len);
+ utf8[len] = 0;
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8);
}
@@ -547,12 +600,36 @@ static int on_escape(const char *bytes, size_t len, void *user)
return 0;
switch(bytes[1]) {
+ case '3': // DECDHL top
+ if(state->mode.leftrightmargin)
+ break;
+ set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_TOP);
+ break;
+
+ case '4': // DECDHL bottom
+ if(state->mode.leftrightmargin)
+ break;
+ set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_BOTTOM);
+ break;
+
+ case '5': // DECSWL
+ if(state->mode.leftrightmargin)
+ break;
+ set_lineinfo(state, state->pos.row, NO_FORCE, DWL_OFF, DHL_OFF);
+ break;
+
+ case '6': // DECDWL
+ if(state->mode.leftrightmargin)
+ break;
+ set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_OFF);
+ break;
+
case '8': // DECALN
{
VTermPos pos;
uint32_t E[] = { 'E', 0 };
for(pos.row = 0; pos.row < state->rows; pos.row++)
- for(pos.col = 0; pos.col < state->cols; pos.col++)
+ for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++)
putglyph(state, E, 1, pos);
break;
}
@@ -684,7 +761,14 @@ static void set_dec_mode(VTermState *state, int num, int val)
break;
case 69: // DECVSSM - vertical split screen mode
+ // DECLRMM - left/right margin mode
state->mode.leftrightmargin = val;
+ if(val) {
+ // Setting DECVSSM must clear doublewidth/doubleheight state of every line
+ for(int row = 0; row < state->rows; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
+ }
+
break;
case 1000:
@@ -869,7 +953,10 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
rect.start_row = state->pos.row;
rect.end_row = state->pos.row + 1;
rect.start_col = state->pos.col;
- rect.end_col = state->cols;
+ if(state->mode.leftrightmargin)
+ rect.end_col = SCROLLREGION_RIGHT(state);
+ else
+ rect.end_col = THISROWWIDTH(state);
scroll(state, rect, 0, -count);
@@ -950,6 +1037,8 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
rect.start_row = state->pos.row + 1; rect.end_row = state->rows;
rect.start_col = 0;
+ for(int row = rect.start_row; row < rect.end_row; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
if(rect.end_row > rect.start_row)
erase(state, rect, selective);
break;
@@ -957,6 +1046,8 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
case 1:
rect.start_row = 0; rect.end_row = state->pos.row;
rect.start_col = 0; rect.end_col = state->cols;
+ for(int row = rect.start_row; row < rect.end_row; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
if(rect.end_col > rect.start_col)
erase(state, rect, selective);
@@ -969,6 +1060,8 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
case 2:
rect.start_row = 0; rect.end_row = state->rows;
rect.start_col = 0; rect.end_col = state->cols;
+ for(int row = rect.start_row; row < rect.end_row; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
erase(state, rect, selective);
break;
}
@@ -983,11 +1076,11 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
switch(CSI_ARG(args[0])) {
case CSI_ARG_MISSING:
case 0:
- rect.start_col = state->pos.col; rect.end_col = state->cols; break;
+ rect.start_col = state->pos.col; rect.end_col = THISROWWIDTH(state); break;
case 1:
rect.start_col = 0; rect.end_col = state->pos.col + 1; break;
case 2:
- rect.start_col = 0; rect.end_col = state->cols; break;
+ rect.start_col = 0; rect.end_col = THISROWWIDTH(state); break;
default:
return 0;
}
@@ -1027,7 +1120,10 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
rect.start_row = state->pos.row;
rect.end_row = state->pos.row + 1;
rect.start_col = state->pos.col;
- rect.end_col = state->cols;
+ if(state->mode.leftrightmargin)
+ rect.end_col = SCROLLREGION_RIGHT(state);
+ else
+ rect.end_col = THISROWWIDTH(state);
scroll(state, rect, 0, count);
@@ -1064,7 +1160,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
rect.end_row = state->pos.row + 1;
rect.start_col = state->pos.col;
rect.end_col = state->pos.col + count;
- UBOUND(rect.end_col, state->cols);
+ UBOUND(rect.end_col, THISROWWIDTH(state));
erase(state, rect, 0);
break;
@@ -1261,16 +1357,28 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
case 0x72: // DECSTBM - DEC custom
state->scrollregion_top = CSI_ARG_OR(args[0], 1) - 1;
state->scrollregion_bottom = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]);
+ LBOUND(state->scrollregion_top, -1);
+ UBOUND(state->scrollregion_top, state->rows);
+ LBOUND(state->scrollregion_bottom, -1);
if(state->scrollregion_top == 0 && state->scrollregion_bottom == state->rows)
state->scrollregion_bottom = -1;
+ else
+ UBOUND(state->scrollregion_bottom, state->rows);
+
break;
case 0x73: // DECSLRM - DEC custom
// Always allow setting these margins, just they won't take effect without DECVSSM
state->scrollregion_left = CSI_ARG_OR(args[0], 1) - 1;
state->scrollregion_right = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]);
+ LBOUND(state->scrollregion_left, -1);
+ UBOUND(state->scrollregion_left, state->cols);
+ LBOUND(state->scrollregion_right, -1);
if(state->scrollregion_left == 0 && state->scrollregion_right == state->cols)
state->scrollregion_right = -1;
+ else
+ UBOUND(state->scrollregion_right, state->cols);
+
break;
case INTERMED('\'', 0x7D): // DECIC
@@ -1311,7 +1419,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
LBOUND(state->pos.row, 0);
UBOUND(state->pos.row, state->rows-1);
LBOUND(state->pos.col, 0);
- UBOUND(state->pos.col, state->cols-1);
+ UBOUND(state->pos.col, THISROWWIDTH(state)-1);
}
updatecursor(state, &oldpos, 1);
@@ -1434,6 +1542,24 @@ static int on_resize(int rows, int cols, void *user)
state->tabstops = newtabstops;
}
+ if(rows != state->rows) {
+ VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo));
+
+ int row;
+ for(row = 0; row < state->rows && row < rows; row++) {
+ newlineinfo[row] = state->lineinfo[row];
+ }
+
+ for( ; row < rows; row++) {
+ newlineinfo[row] = (VTermLineInfo){
+ .doublewidth = 0,
+ };
+ }
+
+ vterm_allocator_free(state->vt, state->lineinfo);
+ state->lineinfo = newlineinfo;
+ }
+
state->rows = rows;
state->cols = cols;
@@ -1483,6 +1609,8 @@ VTermState *vterm_obtain_state(VTerm *vt)
state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8);
+ state->lineinfo = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo));
+
state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u');
if(*state->encoding_utf8.enc->init)
(*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data);
@@ -1516,6 +1644,9 @@ void vterm_state_reset(VTermState *state, int hard)
else
clear_col_tabstop(state, col);
+ for(int row = 0; row < state->rows; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
+
if(state->callbacks && state->callbacks->initpen)
(*state->callbacks->initpen)(state->cbdata);
@@ -1613,3 +1744,8 @@ int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val)
return 0;
}
+
+const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row)
+{
+ return state->lineinfo + row;
+}
diff --git a/src/unicode.c b/src/unicode.c
index ac1748c..69b7682 100644
--- a/src/unicode.c
+++ b/src/unicode.c
@@ -321,12 +321,12 @@ static int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
// ################################
// ### 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);
}
diff --git a/src/utf8.h b/src/utf8.h
index 1c2a2d9..9a336d3 100644
--- a/src/utf8.h
+++ b/src/utf8.h
@@ -12,12 +12,11 @@ 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 nbytes = utf8_seqlen(codepoint);
- str[nbytes] = 0;
-
// This is easier done backwards
int b = nbytes;
while(b > 1) {
diff --git a/src/vterm.c b/src/vterm.c
index 940d1fb..04651d3 100644
--- a/src/vterm.c
+++ b/src/vterm.c
@@ -70,12 +70,12 @@ 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);
}
@@ -108,7 +108,7 @@ void vterm_parser_set_utf8(VTerm *vt, int 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,7 +135,7 @@ void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
va_end(args);
}
-void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
+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);
@@ -148,7 +148,7 @@ void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *f
va_end(args);
}
-void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
+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);
diff --git a/src/vterm_internal.h b/src/vterm_internal.h
index 9a0183e..4bc8e6b 100644
--- a/src/vterm_internal.h
+++ b/src/vterm_internal.h
@@ -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 {
@@ -58,6 +64,10 @@ struct VTermState
/* 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;
@@ -92,6 +102,8 @@ struct VTermState
VTermColor default_fg;
VTermColor default_bg;
+ VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only
+
int fg_index;
int bg_index;
int bold_is_highbright;
@@ -172,6 +184,7 @@ 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);