diff options
Diffstat (limited to 'src/user/terminal')
-rw-r--r-- | src/user/terminal/main.c | 373 | ||||
-rw-r--r-- | src/user/terminal/readline.c | 104 | ||||
-rw-r--r-- | src/user/terminal/terminal.c | 284 |
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 |