Björn Åström 1 yıl önce
ebeveyn
işleme
c1f48abb63
3 değiştirilmiş dosya ile 168 ekleme ve 27 silme
  1. 9 4
      qcmd.c
  2. 146 19
      term.c
  3. 13 4
      term.h

+ 9 - 4
qcmd.c

@@ -31,6 +31,7 @@ struct qcmd {
 	char *cmd;
 	int close_on_exit;
 	struct term terminal;
+	int pango;
 };
 
 struct qcmd state = {0};
@@ -163,9 +164,10 @@ void print_help()
 			"usage: qcmd [options] [command]\n"
 			"  -h, --help           Display this help text.\n"
 			"  -v, --version        Display version information.\n"
-			"  -r, --rows           Number of rows in terminal output.\n"
-			"  -c, --cols           Number of columns in terminal output.\n"
+			"  -r                   Number of rows in terminal output.\n"
+			"  -c                   Number of columns in terminal output.\n"
 			"  -C, --close-on-exit  Close the notification on command exit.\n"
+			"  -p, --pango          Output as pango markup.\n"
 	);
 }
 
@@ -184,10 +186,11 @@ int main(int argc, char *argv[])
 			{"help", no_argument, 0, 'h'},
 			{"version", no_argument, 0, 'v'},
 			{"close-on-exit", no_argument, 0, 'C'},
+			{"pango", no_argument, 0, 'p'},
 			{0, 0, 0, 0},
 		};
 
-		c = getopt_long(argc, argv, "hvCc:r:", long_options, &option_index);
+		c = getopt_long(argc, argv, "hvCpc:r:", long_options, &option_index);
 
 		if (c == -1) {
 			break;
@@ -209,6 +212,8 @@ int main(int argc, char *argv[])
 		case 'c':
 			cols = atoi(optarg);
 			break;
+		case 'p':
+			state.pango = 1;
 		}
 	}
 
@@ -231,7 +236,7 @@ int main(int argc, char *argv[])
 		return EXIT_FAILURE;
 	}
 
-	term_init(&state.terminal, rows, cols);
+	term_init(&state.terminal, rows, cols, state.pango);
 
 	signal(SIGCHLD, cmd_exit);
 	LOG("Forking off command '%s'...", cmd);

+ 146 - 19
term.c

@@ -6,7 +6,18 @@
 
 #define MAX_PARAMS 2
 
-void term_init(struct term *t, int num_rows, int num_cols)
+static char *colors[8] = {
+	"000000",
+	"ff0000",
+	"00ff00",
+	"ffff00",
+	"0000ff",
+	"ff00ff",
+	"00ffff",
+	"ffffff",
+};
+
+void term_init(struct term *t, int num_rows, int num_cols, int pango)
 {
 	t->state = TERM_STATE_GROUND;
 	t->cursor.x = 0;
@@ -17,6 +28,9 @@ void term_init(struct term *t, int num_rows, int num_cols)
 	t->param_idx = 0;
 	t->params[0] = 0;
 	t->params[1] = 0;
+	t->pango = pango;
+	t->sgra.fg = 7;
+	t->sgra.bg = 0;
 	for (int i = 0; i < t->num_rows; i++) {
 		t->rows[i].cells = calloc(t->num_cols, sizeof(struct cell));
 		for (int j = 0; j < t->num_cols; j++) {
@@ -71,13 +85,14 @@ static void term_line_feed(struct term *t)
 
 static void term_print(struct term *t, char c) {
 	struct row *cur_row = &t->rows[t->cursor.y];
+	struct cell *cur_cell = &cur_row->cells[t->cursor.x];
 
-	cur_row->cells[t->cursor.x].c = c;
+	cur_cell->c = c;
+	cur_cell->sgra = t->sgra;
 
-	if (t->cursor.x == t->num_cols - 1) {
+	if (t->cursor.x >= t->num_cols - 1) {
 		term_cursor_move_down(t, 1);
 		t->cursor.x = 0;
-		cur_row->wrapped = true;
 	} else {
 		t->cursor.x++;
 	}
@@ -85,10 +100,13 @@ static void term_print(struct term *t, char c) {
 
 static void term_clear(struct term *t) {
 	t->param_idx = 0;
-	// TODO: also clear
-	//   private flag
-	//   intermediate characters
-	//   final character
+	t->params[0] = 0;
+	t->params[1] = 0;
+
+	// TODO: also clear:
+	//   private flag?
+	//   intermediate characters?
+	//   final character?
 }
 
 static void term_add_param_digit(struct term *t, char c) {
@@ -123,9 +141,91 @@ static void term_collect(struct term *t, char c) {
 
 }
 
+static void term_csi_erase_in_display(struct term *t) {
+	// inclusive
+	int start_x;
+	int start_y;
+	//exclusive
+	int end_x;
+	int end_y;
+
+	switch (t->params[0]) {
+		case 0:
+			start_x = t->cursor.x;
+			start_y = t->cursor.y;
+			end_x = t->num_rows;
+			end_y = t->num_cols;
+			break;
+
+		case 1:
+			start_x = 0;
+			start_y = 0;
+			end_x = t->cursor.x + 1;
+			end_y = t->cursor.y + 1;
+			break;
+
+		// We don't have a scrollback buffer, so 2 and 3 are equivalent
+		case 2:
+		case 3:
+			start_x = 0;
+			start_y = 0;
+			end_x = t->num_rows;
+			end_y = t->num_cols;
+			break;
+	}
+
+	for (int i = start_y; i < end_y; i++) {
+		for (int j = start_x; j < end_x; j++) {
+			// TODO: clear sgr
+			t->rows[i].cells[j].c = ' ';
+		}
+	}
+}
+
+static void term_csi_erase_in_line(struct term *t) {
+	int start_x; // inclusive
+	int end_x; // exclusive
+
+	switch (t->params[0]) {
+		case 0:
+			start_x = t->cursor.x;
+			end_x = t->num_cols;
+			break;
+
+		case 1:
+			start_x = 0;
+			end_x = t->cursor.x + 1;
+			break;
+
+		case 2:
+			start_x = 0;
+			end_x = t->num_cols;
+			break;
+	}
+
+	for (int j = start_x; j < end_x; j++) {
+		// TODO: clear sgr
+		t->rows[t->cursor.y].cells[j].c = ' ';
+	}
+}
+
+static void term_csi_sgr(struct term *t) {
+	int p0 = t->params[0];
+
+	switch (p0) {
+		case 0:
+			t->sgra.fg = 7;
+			t->sgra.bg = 0;
+			break;
+
+		case 30 ... 37: t->sgra.fg = p0 - 30; break;
+		case 40 ... 47: t->sgra.bg = p0 - 40; break;
+	}
+}
+
 static void term_csi_dispatch(struct term *t, char c) {
 	int p0 = t->params[0];
-	//int p1 = t->params[1];
+	int p1 = t->params[1];
 
 	switch (c) {
 		case 'A': term_cursor_move_up(t, p0); break;
@@ -141,6 +241,14 @@ static void term_csi_dispatch(struct term *t, char c) {
 		case 'F': t->cursor.x = 0; term_cursor_move_up(t, p0 == 0 ? 1 : p0); break;
 
 		case 'G': t->cursor.x = p0; break;
+
+		case 'H': t->cursor.y = p0 == 0 ? 0 : p0 - 1; t->cursor.x = p1 == 0 ? 0 : p1 - 1; break;
+
+		case 'J': term_csi_erase_in_display(t); break;
+		
+		case 'K': term_csi_erase_in_line(t); break;
+
+		case 'm': term_csi_sgr(t); break;
 	}
 }
 
@@ -158,7 +266,7 @@ void term_putc(struct term *t, char c)
 
 				case 0x1b: t->state = TERM_STATE_ESC; break;
 
-				case 0x20 ... 0x7f: term_print(t, c);
+				case 0x20 ... 0x7f: term_print(t, c); break;
 			} break;
 
 		case TERM_STATE_ESC:
@@ -177,12 +285,19 @@ void term_putc(struct term *t, char c)
 			} break;
 
 		case TERM_STATE_CSI_ENTRY:
+			// entry
+			term_clear(t);
+
 			// events
 			switch (c) {
 				case 0x00 ... 0x17:
 				case 0x19:
 				case 0x1c ... 0x1f: term_execute(t, c); break;
 
+				case 0x20 ... 0x2f: term_collect(t, c); t->state = TERM_STATE_CSI_INTERMEDIATE; break;
+
+				case 0x3a: t->state = TERM_STATE_CSI_IGNORE; break;
+
 				case 0x3c ... 0x3f: /* Ignore privates??? */ break;
 
 				case 0x30 ... 0x39:
@@ -207,6 +322,8 @@ void term_putc(struct term *t, char c)
 
 				case 0x3a:
 				case 0x3c ... 0x3f: t->state = TERM_STATE_CSI_IGNORE; break;
+				
+				case 0x40 ... 0x7e: term_csi_dispatch(t, c); t->state = TERM_STATE_GROUND; break;
 			} break;
 
 		case TERM_STATE_CSI_INTERMEDIATE:
@@ -216,7 +333,7 @@ void term_putc(struct term *t, char c)
 
 				case 0x30 ... 0x3f: t->state = TERM_STATE_CSI_IGNORE; break;
 
-				case 0x40 ... 0x7e: term_csi_dispatch(t, c); t->state = TERM_STATE_GROUND;
+				case 0x40 ... 0x7e: term_csi_dispatch(t, c); t->state = TERM_STATE_GROUND; break;
 			} break;
 
 		case TERM_STATE_CSI_IGNORE:
@@ -241,22 +358,32 @@ void term_put_string(struct term *t, char *str) {
 
 char *term_to_string(struct term *t)
 {
-	int str_size = t->num_rows * t->num_cols + t->num_rows;
-	char *str = calloc(str_size, sizeof(char));
-	int str_idx = 0;
+	// TODO: don't allocate too much if pango is not used.
+	int str_size = t->num_rows * t->num_cols * 64 + t->num_rows;
+	char *ret = calloc(str_size, sizeof(char));
+	char *s = ret;
 
 	for (int i = 0; i < t->num_rows; i++) {
-		for (int j = 0; j < t->num_cols && str_idx < str_size; j++) {
-			str[str_idx++] = t->rows[i].cells[j].c;
+		for (int j = 0; j < t->num_cols; j++) {
+			struct cell cur_cell = t->rows[i].cells[j];
+			if (t->pango) {
+				// TODO: use snprintf...
+				s += sprintf(s, "<span fgcolor='#%s' bgcolor='#%s'>%c</span>",
+						colors[cur_cell.sgra.fg],
+						colors[cur_cell.sgra.bg],
+						cur_cell.c);
+			} else {
+				*s++ = cur_cell.c;
+			}
 		}
 		if (i == t->num_rows - 1) {
-			str[str_idx++] = '\0';
+			*s++ = '\0';
 		} else {
-			str[str_idx++] = '\n';
+			*s++ = '\n';
 		}
 	}
 
-	return str;
+	return ret;
 }
 
 void term_free(struct term *t)

+ 13 - 4
term.h

@@ -2,6 +2,7 @@
 #define __TERM_H
 
 #include <stdbool.h>
+#include <stdint.h>
 
 #define TERM_MAX_PARAMS 2
 
@@ -19,26 +20,34 @@ struct term_cursor {
 	int y;
 };
 
+struct sgr_attrs {
+	uint8_t bg;
+	uint8_t fg;
+};
+
 struct cell {
+	// No unicode support >:(
 	char c;
+	struct sgr_attrs sgra;
 };
 
 struct row {
-	bool wrapped;
 	struct cell *cells;
 };
 
 struct term {
 	enum term_state state;
-	struct term_cursor cursor;
-	struct row *rows;
 	int num_rows;
 	int num_cols;
 	int params[TERM_MAX_PARAMS];
 	int param_idx;
+	struct term_cursor cursor;
+	struct row *rows;
+	struct sgr_attrs sgra;
+	int pango;
 };
 
-void term_init(struct term *t, int rows, int cols);
+void term_init(struct term *t, int rows, int cols, int pango);
 
 void term_put(struct term *t, char c);
 void term_put_string(struct term *t, char *str);