summaryrefslogtreecommitdiffstats
path: root/src/state.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.c')
-rw-r--r--src/state.c168
1 files changed, 152 insertions, 16 deletions
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;
+}