summaryrefslogtreecommitdiff
path: root/src/user/terminal
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/terminal')
-rw-r--r--src/user/terminal/main.c373
-rw-r--r--src/user/terminal/readline.c104
-rw-r--r--src/user/terminal/terminal.c284
3 files changed, 373 insertions, 388 deletions
diff --git a/src/user/terminal/main.c b/src/user/terminal/main.c
new file mode 100644
index 0000000..15ca6a1
--- /dev/null
+++ b/src/user/terminal/main.c
@@ -0,0 +1,373 @@
+#include <libterm/command.h>
+
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+#include <knob/task.h>
+#include <knob/ipc.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
+
+#define FONT_HARDCODE "berry"
+
+_window_handle_t window;
+uint8_t *pixbuf;
+char *termbuf;
+struct font_info *font;
+
+uint32_t width;
+uint32_t height;
+uint32_t cols = 50;
+uint32_t rows = 15;
+
+uint32_t cursor_y = 0;
+uint32_t cursor_x = 0;
+
+uint8_t bg_color = 0x10;
+uint8_t fg_color = 0x07;
+
+struct waiting_for_key_record {
+ _task_handle_t task;
+ struct waiting_for_key_record *next;
+} *first_key_waiting = 0, *last_key_waiting = 0;
+
+static void draw_char(uint32_t y, uint32_t x, bool inverted) {
+//syslogf("drawing 0x%2h%s at %u, %u", termbuf[y * cols + x], inverted ? " inverted" : "", y, x);
+ put_char(font, termbuf[y * cols + x], pixbuf + y * font->space_height * width + x * font->space_width, width, inverted ? fg_color : bg_color, inverted ? bg_color : fg_color);
+}
+
+static void clear() {
+ for (uint32_t i = 0; i < cols * rows; ++i)
+ termbuf[i] = ' ';
+ for (uint32_t i = 0; i < width * height; ++i)
+ pixbuf[i] = bg_color;
+}
+
+static void scroll_fw() {
+ uint32_t i;
+ for (i = 0; i < cols * (rows - 1); ++i)
+ termbuf[i] = termbuf[i + cols];
+ for (; i < cols * rows; ++i)
+ termbuf[i] = ' ';
+ const uint32_t row_height = font->space_height;
+ for (i = 0; i < width * (height - row_height); ++i)
+ pixbuf[i] = pixbuf[i + width * row_height];
+ for (; i < width * height; ++i)
+ pixbuf[i] = bg_color;
+}
+
+static void cursor_down() {
+ if (cursor_y == rows - 1)
+ scroll_fw();
+ else
+ ++cursor_y;
+}
+
+static void cursor_right() {
+ if (cursor_x == cols - 1) {
+ cursor_x = 0;
+ cursor_down();
+ }
+ else
+ ++cursor_x;
+}
+
+__attribute__ ((pure))
+static uint32_t word_len(const char *sz) {
+ const char *const back = sz;
+ while ((*sz != ' ') && (*sz != '\n') && *sz && (*sz != '\t'))
+ ++sz;
+ return sz - back;
+}
+
+#define MIN_TAB 3
+#define TAB_STOP 4
+
+static void on_newline() {
+ draw_char(cursor_y, cursor_x, false);
+ cursor_x = 0;
+ cursor_down();
+}
+
+static void add_char(char ch);
+
+static void on_tab() {
+ for (uint32_t i = 0; i < MIN_TAB; ++i)
+ add_char(' ');
+ while (cursor_x % TAB_STOP)
+ add_char(' ');
+}
+
+static void add_char(char ch) {
+ if (ch == '\n')
+ on_newline();
+ else if (ch == '\t')
+ on_tab();
+ else {
+ termbuf[cursor_y * cols + cursor_x] = ch;
+ draw_char(cursor_y, cursor_x, false);
+ cursor_right();
+ }
+}
+
+static void add_sz_no_ww(const char *sz) {
+ while (*sz)
+ add_char(*(sz++));
+}
+
+static void add_sn_no_ww(const char *sz, uint32_t l) {
+ for (uint32_t i = 0; i < l; ++i)
+ add_char(sz[i]);
+}
+
+static void add_sz_ww(const char *sz) {
+ while (*sz) {
+ if (*sz == ' ') {
+ ++sz;
+ continue;
+ }
+ if (*sz == '\n') {
+ on_newline();
+ ++sz;
+ continue;
+ }
+ if (*sz == '\t') {
+ on_tab();
+ ++sz;
+ continue;
+ }
+
+ if (cursor_x)
+ add_char(' ');
+
+ const uint32_t len = word_len(sz);
+
+ if ((len > cols - cursor_x) && (len <= cols)) {
+ cursor_x = 0;
+ cursor_down();
+ }
+ add_sn_no_ww(sz, len);
+
+ sz += len;
+ }
+}
+
+char *const sz_empty_backup = "";
+char *sz_from_task = 0;
+uint32_t sz_buf_size = 0;
+
+#define BUF_INCREMENTS 1024
+
+static void get_sn(uint32_t len, _task_handle_t from) {
+ if (sz_buf_size <= len) {
+ if (sz_from_task && (sz_from_task != sz_empty_backup))
+ free_block(sz_from_task);
+ sz_from_task = get_block(sz_buf_size += 1024);
+ if (!sz_from_task) {
+ add_sz_ww("Could not allocate enough memory for sent string. Treating as empty string.\n");
+ sz_buf_size = 0;
+ sz_from_task = sz_empty_backup;
+ return;
+ }
+ }
+
+ const uint32_t real_len = try_read_ipc(from, sz_from_task, len);
+ sz_from_task[real_len] = '\0';
+}
+
+static void set_dimensions(uint32_t new_rows, uint32_t new_cols) {
+ free_block(termbuf);
+ free_block(pixbuf);
+ //from here until _resize, the kernel may draw garbage if it
+ // needs to redraw the window. it won't page fault though.
+
+ rows = new_rows;
+ cols = new_cols;
+ termbuf = get_block(rows * cols);
+
+ width = cols * font->space_width;
+ height = cols * font->space_height;
+ pixbuf = get_block(width * height);
+
+ cursor_y = 0;
+ cursor_x = 0;
+ clear();
+
+ _resize_window(window, width, height, pixbuf);
+}
+
+void draw_all() {
+ for (uint32_t y = 0; y < rows; ++y)
+ for (uint32_t x = 0; x < cols; ++x)
+ draw_char(y, x, false);
+ draw_char(cursor_y, cursor_x, true);
+}
+
+//#include <knob/format.h>
+
+void main(const char *cmd) {
+//syslogf(" this task: 0x%2h", this_task);
+//syslogf(" stdio task: 0x%2h", stdio_task);
+//syslogf("calling task: 0x%2h", calling_task);
+
+ font = get_font(FONT_HARDCODE);
+ if (!font)
+ return;
+
+ termbuf = get_block(cols * rows);
+ width = cols * font->space_width;
+ height = rows * font->space_height;
+ pixbuf = get_block(width * height);
+ clear();
+ add_sz_ww("Portland Terminal\n");
+ window = _new_window(width, height, pixbuf);
+ _paint_window(window);
+
+ _task_handle_t child_handle = run_command(cmd, this_task);
+ if (!child_handle) {
+ add_sz_ww("Failed to run passed command. Press any key to close.\n");
+ _paint_window(window);
+ while (1) {
+ struct window_action action;
+ _get_win_action(window, &action);
+ if (action.action_type == NOT_READY) {
+ _wait_for_action();
+ _yield_task();
+ }
+ else if (action.action_type == KEY_DOWN)
+ return;
+ }
+ }
+
+ while (1) {
+ if (first_key_waiting) {
+ struct window_action action;
+ _get_win_action(window, &action);
+ if (action.action_type == KEY_DOWN) {
+ union terminal_response rs = {
+ .as_key = action.as_key
+ };
+ try_send_ipc(first_key_waiting->task, &rs, sizeof(union terminal_response));
+ free_block(first_key_waiting);
+ first_key_waiting = first_key_waiting->next;
+ if (!first_key_waiting)
+ last_key_waiting = 0;
+ continue;
+ }
+ }
+
+ _task_handle_t from = _find_unread_ipc();
+ if (!from) {
+ if (!_is_task_running(child_handle))
+ return;
+
+ _wait_for_action();
+ _wait_for_any_ipc_sent();
+ _wait_for_task(child_handle);
+ _yield_task();
+ continue;
+ }
+
+ struct terminal_command request;
+ const uint32_t read = try_read_ipc(from, &request, sizeof(struct terminal_command));
+ if (read != sizeof(struct terminal_command)) {
+ syslogf("received %u / %u bytes of a command from 0x%2x", read, sizeof(struct terminal_command), from);
+ continue;
+ }
+ //syslogf("received full command from 0x%2x", from);
+
+ switch (request.kind) {
+ case SET_DIMENSIONS:
+ set_dimensions(request.as_coords.y, request.as_coords.x);
+ continue;
+ union terminal_response rs;
+ case GET_DIMENSIONS:
+ rs.as_coords.y = rows;
+ rs.as_coords.x = cols;
+ try_send_ipc(from, &rs, sizeof(union terminal_response));
+ continue;
+ case PAINT:
+ _paint_window(window);
+ continue;
+ case CLEAR:
+ clear();
+ cursor_y = 0;
+ cursor_x = 0;
+ draw_char(0, 0, true);
+ continue;
+ case SET_COLOR:
+ fg_color = request.as_color.fg;
+ bg_color = request.as_color.bg;
+ draw_all();
+ continue;
+ case SET_CURSOR:
+ draw_char(cursor_y, cursor_x, false);
+ cursor_y = request.as_coords.y;
+ cursor_x = request.as_coords.x;
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case CURSOR_LEFT:
+ draw_char(cursor_y, cursor_x, false);
+ if (cursor_x)
+ --cursor_x;
+ else if (cursor_y) {
+ cursor_x = cols - 1;
+ --cursor_y;
+ }
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case CURSOR_RIGHT:
+ draw_char(cursor_y, cursor_x, false);
+ cursor_right();
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case CURSOR_UP:
+ if (cursor_y) {
+ draw_char(cursor_y, cursor_x, false);
+ --cursor_y;
+ draw_char(cursor_y, cursor_x, true);
+ }
+ continue;
+ case CURSOR_DOWN:
+ draw_char(cursor_y, cursor_x, false);
+ if (cursor_y == rows - 1)
+ scroll_fw();
+ else
+ ++cursor_y;
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case ADD_CHAR:
+ add_char(request.as_char);
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case ADD_SN:
+ draw_char(cursor_y, cursor_x, false);
+ get_sn(request.as_uint, from);
+ add_sz_ww(sz_from_task);
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case ADD_SN_NO_WORDWRAP:
+ draw_char(cursor_y, cursor_x, false);
+ get_sn(request.as_uint, from);
+ add_sz_no_ww(sz_from_task);
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ struct waiting_for_key_record *new_record;
+ case GET_KEY:
+ new_record = get_block(sizeof(struct waiting_for_key_record));
+ if (last_key_waiting)
+ last_key_waiting->next = new_record;
+ else
+ first_key_waiting = new_record;
+ last_key_waiting = new_record;
+ new_record->task = from;
+ new_record->next = 0;
+ continue;
+ default:
+ add_sz_ww("Bad terminal command received, ignoring.\n");
+ continue;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/user/terminal/readline.c b/src/user/terminal/readline.c
deleted file mode 100644
index 37ef54b..0000000
--- a/src/user/terminal/readline.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include <terminal/terminal.h>
-
-#include <knob/format.h>
-#include <knob/heap.h>
-#include <knob/key.h>
-
-#include <pland/syscall.h>
-
-#include <stdint.h>
-
-//returns length of string without null terminator
-//max_length doesn't include null terminator
-uint32_t read_line(char *sz, uint32_t max_length, const char *prompt) {
- uint32_t i = 0;
- uint32_t l = 0;
-
- term_add_sz_no_ww(prompt);
- paint_term();
-
- const _window_handle_t handle = active_term->window;
- struct window_action action;
- while (1) {
- _get_win_action(handle, &action);
- switch (action.action_type) {
- case NOT_READY:
- _wait_for_action();
- _yield_task();
- continue;
- case KEY_DOWN:
- //;char *const debug_msg = format("got key 0x%2x, 0x%3x", action.as_key.key_id, action.as_key.modifiers);
- // _system_log(debug_msg);
- // free_block(debug_msg);
- switch (action.as_key.key_id) {
- case KEY_DELETE:
- if (i != l) {
- cursor_right();
- ++i;
- }
- case KEY_BSPACE:
- if (!i)
- continue;
- --l;
- --i;
- for (uint8_t j = i; j < l; ++j)
- sz[j] = sz[j + 1];
- sz[l] = '\0';
- cursor_left();
- uint32_t cursor_backup_x = active_term->cursor_x;
- uint32_t cursor_backup_y = active_term->cursor_y;
- term_add_sz_no_ww(sz + i);
- term_add_char(' ');
- move_cursor(cursor_backup_y, cursor_backup_x);
- paint_term();
- continue;
- case KEY_ENTER:
- term_newline();
- paint_term();
- sz[l] = '\0';
- return l;
- case KEY_HOME:
- case KEY_UP_ARROW:
- for (; i; --i)
- cursor_left();
- paint_term();
- continue;
- case KEY_END:
- case KEY_DOWN_ARROW:
- for (; i != l; ++i)
- cursor_right();
- paint_term();
- continue;
- case KEY_LEFT_ARROW:
- if (i) {
- cursor_left();
- paint_term();
- --i;
- }
- continue;
- case KEY_RIGHT_ARROW:
- if (i != l) {
- cursor_right();
- paint_term();
- ++i;
- }
- continue;
- default:
- if (i == max_length)
- continue;
- char ch = key_to_char(action.as_key);
- if (ch) {
- term_add_char(ch);
- paint_term();
- sz[i] = ch;
- if (i == l)
- ++l;
- ++i;
- }
- continue;
- }
- default:
- continue;
- }
- }
-} \ No newline at end of file
diff --git a/src/user/terminal/terminal.c b/src/user/terminal/terminal.c
deleted file mode 100644
index 7961fd5..0000000
--- a/src/user/terminal/terminal.c
+++ /dev/null
@@ -1,284 +0,0 @@
-#include <terminal/terminal.h>
-
-#include <libfont/fonts.h>
-
-#include <knob/format.h>
-#include <knob/heap.h>
-
-struct term_list_entry {
- struct terminal term;
- struct term_list_entry *next;
- struct term_list_entry *prev;
-};
-
-struct term_list_entry *last_term = 0;
-struct terminal *active_term = 0;
-
-struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows) {
- if (!font)
- return 0;
-
- struct term_list_entry *next_entry = get_block(sizeof(struct term_list_entry));
- if (!next_entry)
- return 0;
-
- char *const cb = get_block(cols * rows);
-
- if (!cb) {
- free_block(next_entry);
- return 0;
- }
-
- const uint32_t w = cols * font->space_width;
- const uint32_t h = rows * font->space_height;
-
- uint8_t *const pb = get_block(w * h);
- if (!pb) {
- free_block(next_entry);
- free_block(cb);
- return 0;
- }
-
- _window_handle_t win = _new_window(w, h, pb);
- if (!win) {
- free_block(next_entry);
- free_block(cb);
- free_block(pb);
- return 0;
- }
-
- for (char *i = cb; i < cb + cols * rows; ++i)
- *i = ' ';
- for (uint8_t *i = pb; i < pb + w * h; ++i)
- *i = 0x10;
-
- next_entry->term.window = win;
- next_entry->term.pixbuf = pb;
- next_entry->term.window_width = w;
- next_entry->term.window_height = h;
-
- next_entry->term.font = font;
-
- next_entry->term.cols = cols;
- next_entry->term.rows = rows;
- next_entry->term.charbuf = cb;
-
- next_entry->term.cursor_y = 0;
- next_entry->term.cursor_x = 0;
-
- next_entry->term.fg = 0x0f;
- next_entry->term.bg = 0x10;
-
- next_entry->prev = last_term;
- next_entry->next = 0;
-
- if (last_term)
- last_term->next = next_entry;
- last_term = next_entry;
-
- return (struct terminal *)next_entry;
-}
-
-void del_term(struct terminal *term) {
- _delete_window(term->window);
- free_block(term->pixbuf);
- free_block(term->charbuf);
-
- free_block(term);//coincides with the term_list_entry
- if (active_term == term)
- active_term = 0;
-
- for (struct term_list_entry *i = last_term; i; i = i->prev)
- if (i == (struct term_list_entry *)term) {
- if (i->prev)
- i->prev->next = i->next;
- if (i->next)
- i->next->prev = i->prev;
- if (i == last_term)
- last_term = i->prev;
- return;
- }
-}
-
-static void draw_char(uint32_t y, uint32_t x, bool inverted) {
- put_char(active_term->font, active_term->charbuf[y * active_term->cols + x], active_term->pixbuf + (y * active_term->cols * active_term->font->space_height + x) * active_term->font->space_width, active_term->window_width, inverted ? active_term->fg : active_term->bg, inverted ? active_term->bg : active_term->fg);
-}
-
-static void draw_cursor() {
- draw_char(active_term->cursor_y, active_term->cursor_x, true);
-}
-
-void paint_term() {
- _paint_window(active_term->window);
-}
-
-void move_cursor(uint32_t new_y, uint32_t new_x) {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
- active_term->cursor_y = new_y;
- active_term->cursor_x = new_x;
- draw_cursor();
-}
-
-static void redraw_term() {
- for (uint32_t y = 0; y < active_term->rows; ++y)
- for (uint32_t x = 0; x < active_term->cols; ++x)
- draw_char(y, x, false);
- draw_cursor();
-}
-
-void set_color(uint8_t fg, uint8_t bg) {
- active_term->fg = fg;
- active_term->bg = bg;
- redraw_term();
-}
-
-void clear_term() {
- for (char *i = active_term->charbuf, *const e = i + active_term->cols * active_term->rows; i != e; ++i)
- *i = ' ';
- for (uint8_t *i = active_term->pixbuf, *const e = i + active_term->window_width * active_term->window_height; i != e; ++i)
- *i = active_term->bg;
- move_cursor(0, 0);
-}
-
-void cursor_up() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
- if (active_term->cursor_y)
- --active_term->cursor_y;
- else
- //eventually, maybe scroll back through a longer terminal buffer
- active_term->cursor_x = 0;
- draw_cursor();
-}
-
-void cursor_left() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
- if (active_term->cursor_x) {
- --active_term->cursor_x;
- draw_cursor();
- }
- else {
- active_term->cursor_x = active_term->cols - 1;
- cursor_up();
- }
-}
-
-void cursor_down() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
-
- const uint32_t rows = active_term->rows;
-
- if (++active_term->cursor_y == rows) {
- --active_term->cursor_y;
-
- char *const cb = active_term->charbuf;
- uint8_t *const pb = active_term->pixbuf;
- const uint32_t cols = active_term->cols;
- const uint32_t fw = active_term->font->space_width;
- const uint32_t fh = active_term->font->space_height;
-
- char *to;
- for (to = cb; to < cb + (rows - 1) * cols; ++to)
- *to = *(to + cols);
- for (; to < cb + rows * cols; ++to)
- *to = ' ';
- uint8_t *pto;
- for (pto = pb; pto < pb + cols * fw * (rows - 1) * fh; ++pto)
- *pto = *(pto + cols * fw * fh);
- for (; pto < pb + cols * fw * rows * fh; ++pto)
- *pto = active_term->bg;
- }
-
- draw_cursor();
-}
-
-void cursor_right() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
-
- if (++active_term->cursor_x == active_term->cols)
- term_newline();
- else
- draw_cursor();
-}
-
-void term_newline() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
- active_term->cursor_x = 0;
- cursor_down();
-}
-
-void term_add_char(char ch) {
- if (ch == '\n') {
- term_newline();
- return;
- }
-//char *const debug_msg = format("charbuf[%u] = '%c'", active_term->cursor_y * active_term->cols + active_term->cursor_x, ch);
-//_system_log(debug_msg);
-//free_block(debug_msg);
- active_term->charbuf[active_term->cursor_y * active_term->cols + active_term->cursor_x] = ch;
- cursor_right();
-}
-
-void term_add_sz_no_ww(const char *sz) {
- while (*sz)
- term_add_char(*(sz++));
-}
-
-#define MIN_TAB 3
-#define TAB_STEP 4
-
-void term_add_sz(const char *sz) {
- //TODO: special hyphen handling
- const char *word = sz;
- while (1)
- if (!*sz || (*sz == ' ') || (*sz == '\n') || (*sz == '\t')) {
- const uint32_t len = sz - word;
- if ((active_term->cursor_x + len > active_term->cols) && (len <= active_term->cols) && active_term->cols)
- term_newline();
- for (const char *i = word; i < sz; ++i)
- term_add_char(*i);
- while ((*sz == ' ') || (*sz == '\n') || (*sz == '\t')) {
- if (*sz == '\n')
- term_newline();
- else if (*sz == '\t') {
- for (uint8_t i = 0; i < MIN_TAB; ++i)
- cursor_right();
- while (active_term->cursor_x % TAB_STEP)
- cursor_right();
- }
- ++sz;
- }
- if (!*sz)
- return;
- if (active_term->cursor_x)
- term_add_char(' ');
- word = sz;
- }
- else
- ++sz;
-}
-
-void term_addf_no_ww_v(const char *fmt, va_list args) {
- char *const msg = format_v(fmt, args);
- term_add_sz_no_ww(msg);
- free_block(msg);
-}
-
-void term_addf_no_ww(const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- term_addf_no_ww_v(fmt, args);
- va_end(args);
-}
-
-void term_addf_v(const char *fmt, va_list args) {
- char *const msg = format_v(fmt, args);
- term_add_sz(msg);
- free_block(msg);
-}
-
-void term_addf(const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- term_addf_v(fmt, args);
- va_end(args);
-} \ No newline at end of file