mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
fix(input): update terminal and txtedit to use UTF-8 input subsystem.
This commit is contained in:
parent
915e33434e
commit
8006a83449
3 changed files with 197 additions and 88 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "utf-8.h"
|
||||||
|
|
||||||
#define MAX_LINE 512
|
#define MAX_LINE 512
|
||||||
#define MAX_ARGS 32
|
#define MAX_ARGS 32
|
||||||
|
|
@ -576,9 +577,6 @@ static void get_time_string(char *out, int max_len) {
|
||||||
str_append(out, mm, max_len);
|
str_append(out, mm, max_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void format_prompt(const char *tmpl, char *out, int max_len) {
|
|
||||||
render_prompt(tmpl, out, max_len, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int split_args(char *line, char *argv[], int max_args) {
|
static int split_args(char *line, char *argv[], int max_args) {
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
|
|
@ -1466,8 +1464,13 @@ static int read_line(char *out, int max_len, const char *prompt_tmpl) {
|
||||||
|
|
||||||
if (ch == '\b' || ch == 127) {
|
if (ch == '\b' || ch == 127) {
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
len--;
|
// Find previous UTF-8 character boundary
|
||||||
|
const char *prev = text_prev_utf8(out, out + len);
|
||||||
|
len = (int)(prev - out);
|
||||||
out[len] = 0;
|
out[len] = 0;
|
||||||
|
|
||||||
|
// Send only ONE backspace sequence to the terminal
|
||||||
|
// because the terminal is now codepoint-based.
|
||||||
sys_write(1, "\b \b", 3);
|
sys_write(1, "\b \b", 3);
|
||||||
}
|
}
|
||||||
search_mode = false;
|
search_mode = false;
|
||||||
|
|
@ -1590,7 +1593,7 @@ static int read_line(char *out, int max_len, const char *prompt_tmpl) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch >= 32 && len < max_len - 1) {
|
if (((unsigned char)ch >= 32 || (signed char)ch < 0) && len < max_len - 1) {
|
||||||
out[len++] = ch;
|
out[len++] = ch;
|
||||||
out[len] = 0;
|
out[len] = 0;
|
||||||
sys_write(1, &ch, 1);
|
sys_write(1, &ch, 1);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include "libc/libui.h"
|
#include "libc/libui.h"
|
||||||
#include "libc/input.h"
|
#include "libc/input.h"
|
||||||
#include <stdbool.h>
|
#include "utf-8.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define DEFAULT_COLS 116
|
#define DEFAULT_COLS 116
|
||||||
|
|
@ -25,7 +25,7 @@ static int g_line_h = 10;
|
||||||
#define LINE_MAX 256
|
#define LINE_MAX 256
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char c;
|
uint32_t c;
|
||||||
uint32_t color;
|
uint32_t color;
|
||||||
} CharCell;
|
} CharCell;
|
||||||
|
|
||||||
|
|
@ -52,6 +52,13 @@ typedef struct {
|
||||||
|
|
||||||
bool colors_enabled;
|
bool colors_enabled;
|
||||||
|
|
||||||
|
// UTF-8 decoding state
|
||||||
|
uint32_t utf8_codepoint;
|
||||||
|
int utf8_expected;
|
||||||
|
int utf8_received;
|
||||||
|
|
||||||
|
int unacknowledged_chars;
|
||||||
|
|
||||||
// for color
|
// for color
|
||||||
char current_input[LINE_MAX];
|
char current_input[LINE_MAX];
|
||||||
int input_len;
|
int input_len;
|
||||||
|
|
@ -221,7 +228,7 @@ static void session_scroll(TerminalSession *s) {
|
||||||
s->cursor_col = 0;
|
s->cursor_col = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void session_put_char(TerminalSession *s, char c) {
|
static void session_put_char(TerminalSession *s, uint32_t c) {
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
s->cursor_row++;
|
s->cursor_row++;
|
||||||
s->cursor_col = 0;
|
s->cursor_col = 0;
|
||||||
|
|
@ -234,6 +241,7 @@ static void session_put_char(TerminalSession *s, char c) {
|
||||||
}
|
}
|
||||||
if (c == '\b') {
|
if (c == '\b') {
|
||||||
if (s->cursor_col > 0) s->cursor_col--;
|
if (s->cursor_col > 0) s->cursor_col--;
|
||||||
|
if (s->unacknowledged_chars < 0) s->unacknowledged_chars++;
|
||||||
int idx = s->cursor_row * g_cols + s->cursor_col;
|
int idx = s->cursor_row * g_cols + s->cursor_col;
|
||||||
if (idx >= 0 && idx < g_cols * g_rows) {
|
if (idx >= 0 && idx < g_cols * g_rows) {
|
||||||
s->cells[idx].c = ' ';
|
s->cells[idx].c = ' ';
|
||||||
|
|
@ -257,6 +265,7 @@ static void session_put_char(TerminalSession *s, char c) {
|
||||||
s->cells[idx].color = s->fg_color;
|
s->cells[idx].color = s->fg_color;
|
||||||
}
|
}
|
||||||
s->cursor_col++;
|
s->cursor_col++;
|
||||||
|
if (s->unacknowledged_chars > 0) s->unacknowledged_chars--;
|
||||||
if (s->cursor_col >= g_cols) {
|
if (s->cursor_col >= g_cols) {
|
||||||
s->cursor_col = 0;
|
s->cursor_col = 0;
|
||||||
s->cursor_row++;
|
s->cursor_row++;
|
||||||
|
|
@ -290,7 +299,7 @@ static void ansi_handle_sgr(TerminalSession *s) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ansi_finalize(TerminalSession *s, char cmd) {
|
static void ansi_finalize(TerminalSession *s, uint32_t cmd) {
|
||||||
if (cmd == 'm') {
|
if (cmd == 'm') {
|
||||||
ansi_handle_sgr(s);
|
ansi_handle_sgr(s);
|
||||||
} else if (cmd == 'J') {
|
} else if (cmd == 'J') {
|
||||||
|
|
@ -339,36 +348,75 @@ static void ansi_finalize(TerminalSession *s, char cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void session_process_char(TerminalSession *s, char c) {
|
static void session_process_char(TerminalSession *s, char c) {
|
||||||
|
uint8_t b = (uint8_t)c;
|
||||||
|
if (s->utf8_expected == 0) {
|
||||||
|
if (b < 128) {
|
||||||
|
s->utf8_codepoint = b;
|
||||||
|
s->utf8_expected = 0;
|
||||||
|
} else if ((b & 0xE0) == 0xC0) {
|
||||||
|
s->utf8_codepoint = b & 0x1F;
|
||||||
|
s->utf8_expected = 1;
|
||||||
|
s->utf8_received = 1;
|
||||||
|
return;
|
||||||
|
} else if ((b & 0xF0) == 0xE0) {
|
||||||
|
s->utf8_codepoint = b & 0x0F;
|
||||||
|
s->utf8_expected = 2;
|
||||||
|
s->utf8_received = 1;
|
||||||
|
return;
|
||||||
|
} else if ((b & 0xF8) == 0xF0) {
|
||||||
|
s->utf8_codepoint = b & 0x07;
|
||||||
|
s->utf8_expected = 3;
|
||||||
|
s->utf8_received = 1;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((b & 0xC0) == 0x80) {
|
||||||
|
s->utf8_codepoint = (s->utf8_codepoint << 6) | (b & 0x3F);
|
||||||
|
s->utf8_received++;
|
||||||
|
if (s->utf8_received <= s->utf8_expected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s->utf8_expected = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cp = s->utf8_codepoint;
|
||||||
|
s->utf8_expected = 0;
|
||||||
|
|
||||||
if (s->ansi_state == 0) {
|
if (s->ansi_state == 0) {
|
||||||
if (c == 27) {
|
if (cp == 27) {
|
||||||
s->ansi_state = 1;
|
s->ansi_state = 1;
|
||||||
s->ansi_param_count = 0;
|
s->ansi_param_count = 0;
|
||||||
s->ansi_params[0] = 0;
|
s->ansi_params[0] = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session_put_char(s, c);
|
session_put_char(s, cp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->ansi_state == 1) {
|
if (s->ansi_state == 1) {
|
||||||
if (c == '[') {
|
if (cp == '[') {
|
||||||
s->ansi_state = 2;
|
s->ansi_state = 2;
|
||||||
s->ansi_param_count = 0;
|
s->ansi_param_count = 0;
|
||||||
s->ansi_params[0] = 0;
|
s->ansi_params[0] = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s->ansi_state = 0;
|
s->ansi_state = 0;
|
||||||
session_put_char(s, c);
|
session_put_char(s, cp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->ansi_state == 2) {
|
if (s->ansi_state == 2) {
|
||||||
if (c >= '0' && c <= '9') {
|
if (cp >= '0' && cp <= '9') {
|
||||||
int idx = s->ansi_param_count;
|
int idx = s->ansi_param_count;
|
||||||
s->ansi_params[idx] = s->ansi_params[idx] * 10 + (c - '0');
|
s->ansi_params[idx] = s->ansi_params[idx] * 10 + (cp - '0');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (c == ';') {
|
if (cp == ';') {
|
||||||
if (s->ansi_param_count < 7) {
|
if (s->ansi_param_count < 7) {
|
||||||
s->ansi_param_count++;
|
s->ansi_param_count++;
|
||||||
s->ansi_params[s->ansi_param_count] = 0;
|
s->ansi_params[s->ansi_param_count] = 0;
|
||||||
|
|
@ -376,7 +424,7 @@ static void session_process_char(TerminalSession *s, char c) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s->ansi_param_count++;
|
s->ansi_param_count++;
|
||||||
ansi_finalize(s, c);
|
ansi_finalize(s, cp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -708,6 +756,9 @@ static void draw_session(TerminalSession *s) {
|
||||||
int total_lines = s->scroll_count + g_rows;
|
int total_lines = s->scroll_count + g_rows;
|
||||||
int bottom_line = total_lines - 1 - s->scroll_offset;
|
int bottom_line = total_lines - 1 - s->scroll_offset;
|
||||||
int top_line = bottom_line - (g_rows - 1);
|
int top_line = bottom_line - (g_rows - 1);
|
||||||
|
int input_char_len = text_strlen_utf8(s->current_input);
|
||||||
|
int visible_len = input_char_len - s->unacknowledged_chars;
|
||||||
|
if (visible_len < 0) visible_len = 0;
|
||||||
|
|
||||||
for (int row = 0; row < g_rows; row++) {
|
for (int row = 0; row < g_rows; row++) {
|
||||||
int line_index = top_line + row;
|
int line_index = top_line + row;
|
||||||
|
|
@ -723,22 +774,24 @@ static void draw_session(TerminalSession *s) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int input_start = s->cursor_col - s->input_len;
|
int input_start = s->cursor_col - visible_len;
|
||||||
if (input_start < 0) input_start = 0;
|
if (input_start < 0) input_start = 0;
|
||||||
if (input_start >= g_cols) input_start = g_cols - 1;
|
if (input_start >= g_cols) input_start = g_cols - 1;
|
||||||
|
|
||||||
// lenght of a command
|
char cmd[64];
|
||||||
int cmd_len = 0;
|
int i = 0;
|
||||||
while (cmd_len < s->input_len &&
|
while (i < s->input_len && s->current_input[i] != ' ' && s->current_input[i] != '\t' && i < 63) {
|
||||||
s->current_input[cmd_len] != ' ') {
|
cmd[i] = s->current_input[i];
|
||||||
cmd_len++;
|
i++;
|
||||||
}
|
}
|
||||||
|
cmd[i] = 0;
|
||||||
|
int cmd_char_len = text_strlen_utf8(cmd);
|
||||||
|
|
||||||
int input_end = input_start + cmd_len;
|
int input_end = input_start + cmd_char_len;
|
||||||
if (input_end > g_cols) input_end = g_cols;
|
if (input_end > g_cols) input_end = g_cols;
|
||||||
|
|
||||||
for (int col = 0; col < g_cols; col++) {
|
for (int col = 0; col < g_cols; col++) {
|
||||||
char ch = ' ';
|
uint32_t ch = ' ';
|
||||||
uint32_t color = s->fg_color;
|
uint32_t color = s->fg_color;
|
||||||
|
|
||||||
if (line && col < line_cols) {
|
if (line && col < line_cols) {
|
||||||
|
|
@ -753,10 +806,13 @@ static void draw_session(TerminalSession *s) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char str[2] = { ch, 0 };
|
char out[5];
|
||||||
|
int len = text_encode_utf8(ch, out);
|
||||||
|
out[len] = 0;
|
||||||
|
|
||||||
int x = col * g_char_w;
|
int x = col * g_char_w;
|
||||||
int y = base_y + row * g_line_h;
|
int y = base_y + row * g_line_h;
|
||||||
ui_draw_string(g_win, x, y, str, color);
|
ui_draw_string(g_win, x, y, out, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -784,6 +840,10 @@ static void tab_init(TerminalSession *s, int tty_id, int bsh_pid) {
|
||||||
|
|
||||||
s->input_len = 0;
|
s->input_len = 0;
|
||||||
s->current_input[0] = 0;
|
s->current_input[0] = 0;
|
||||||
|
s->utf8_codepoint = 0;
|
||||||
|
s->utf8_expected = 0;
|
||||||
|
s->utf8_received = 0;
|
||||||
|
s->unacknowledged_chars = 0;
|
||||||
session_reset_colors(s);
|
session_reset_colors(s);
|
||||||
scrollback_init(s);
|
scrollback_init(s);
|
||||||
|
|
||||||
|
|
@ -1024,30 +1084,11 @@ static void update_input_color(TerminalSession *s) {
|
||||||
|
|
||||||
static void handle_key(gui_event_t *ev) {
|
static void handle_key(gui_event_t *ev) {
|
||||||
TerminalSession *s = &g_tabs[g_active_tab];
|
TerminalSession *s = &g_tabs[g_active_tab];
|
||||||
char c = (char)ev->arg1;
|
int legacy = ev->arg1;
|
||||||
bool ctrl = ev->arg3 != 0;
|
bool ctrl = ev->arg3 != 0;
|
||||||
|
uint32_t codepoint = (uint32_t)ev->arg4;
|
||||||
|
|
||||||
// create new tab with ctrl + t
|
if (ctrl && (legacy == 'c' || legacy == 'C')) {
|
||||||
if (ctrl && c == 't') {
|
|
||||||
int idx = create_tab();
|
|
||||||
if (idx >= 0) g_active_tab = idx;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// switch to tab right, with ctrl + arrow right
|
|
||||||
if (ctrl && c == KEY_RIGHT) {
|
|
||||||
if (g_tab_count > 0) g_active_tab = (g_active_tab + 1) % g_tab_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// switch to tab left, with ctrl + arrow left
|
|
||||||
if (ctrl && c == KEY_LEFT) {
|
|
||||||
if (g_tab_count > 0) g_active_tab = (g_active_tab + g_tab_count - 1) % g_tab_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// kill the processus with ctrl + c
|
|
||||||
if (ctrl && (c == 'c' || c == 'C')) {
|
|
||||||
int fg = sys_tty_get_fg(s->tty_id);
|
int fg = sys_tty_get_fg(s->tty_id);
|
||||||
if (fg > 0) {
|
if (fg > 0) {
|
||||||
sys_tty_kill_fg(s->tty_id);
|
sys_tty_kill_fg(s->tty_id);
|
||||||
|
|
@ -1059,30 +1100,84 @@ static void handle_key(gui_event_t *ev) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create new tab with ctrl + t
|
||||||
|
if (ctrl && (legacy == 't' || legacy == 'T')) {
|
||||||
|
int idx = create_tab();
|
||||||
|
if (idx >= 0) g_active_tab = idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch to tab right, with ctrl + arrow right
|
||||||
|
if (ctrl && legacy == KEY_RIGHT) {
|
||||||
|
if (g_tab_count > 0) g_active_tab = (g_active_tab + 1) % g_tab_count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch to tab left, with ctrl + arrow left
|
||||||
|
if (ctrl && legacy == KEY_LEFT) {
|
||||||
|
if (g_tab_count > 0) g_active_tab = (g_active_tab + g_tab_count - 1) % g_tab_count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (legacy == KEY_LEFT) {
|
||||||
|
char seq[] = { 27, '[', 'D' };
|
||||||
|
sys_tty_write_in(s->tty_id, seq, 3);
|
||||||
|
return;
|
||||||
|
} else if (legacy == KEY_RIGHT) {
|
||||||
|
char seq[] = { 27, '[', 'C' };
|
||||||
|
sys_tty_write_in(s->tty_id, seq, 3);
|
||||||
|
return;
|
||||||
|
} else if (legacy == KEY_UP) {
|
||||||
|
char seq[] = { 27, '[', 'A' };
|
||||||
|
sys_tty_write_in(s->tty_id, seq, 3);
|
||||||
|
return;
|
||||||
|
} else if (legacy == KEY_DOWN) {
|
||||||
|
char seq[] = { 27, '[', 'B' };
|
||||||
|
sys_tty_write_in(s->tty_id, seq, 3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
if (c == KEY_BACKSPACE) {
|
if (legacy == KEY_BACKSPACE) {
|
||||||
if (s->input_len > 0) {
|
if (s->input_len > 0) {
|
||||||
s->input_len--;
|
// Find previous UTF-8 character boundary
|
||||||
|
const char *prev = text_prev_utf8(s->current_input, s->current_input + s->input_len);
|
||||||
|
s->input_len = (int)(prev - s->current_input);
|
||||||
s->current_input[s->input_len] = 0;
|
s->current_input[s->input_len] = 0;
|
||||||
}
|
}
|
||||||
} else if (c >= 32 && c < 127) {
|
} else if (codepoint >= 32 && codepoint != 127) {
|
||||||
if (s->input_len < LINE_MAX - 1) {
|
char utf8[4];
|
||||||
s->current_input[s->input_len++] = c;
|
int len = text_encode_utf8(codepoint, utf8);
|
||||||
|
if (len > 0 && s->input_len + len < LINE_MAX - 1) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
s->current_input[s->input_len + i] = utf8[i];
|
||||||
|
}
|
||||||
|
s->input_len += len;
|
||||||
s->current_input[s->input_len] = 0;
|
s->current_input[s->input_len] = 0;
|
||||||
|
s->unacknowledged_chars++;
|
||||||
}
|
}
|
||||||
|
} else if (legacy == KEY_ENTER) {
|
||||||
|
s->input_color = 0xFFFFFFFF;
|
||||||
|
s->input_len = 0;
|
||||||
|
s->current_input[0] = 0;
|
||||||
|
s->unacknowledged_chars = 0;
|
||||||
|
} else if (legacy == KEY_BACKSPACE) {
|
||||||
|
s->unacknowledged_chars--;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_input_color(s);
|
update_input_color(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == KEY_ENTER) {
|
if (codepoint >= 32 && codepoint != 127) {
|
||||||
s->input_color = 0xFFFFFFFF;
|
char utf8[4];
|
||||||
s->input_len = 0;
|
int len = text_encode_utf8(codepoint, utf8);
|
||||||
s->current_input[0] = 0;
|
if (len > 0) {
|
||||||
|
sys_tty_write_in(s->tty_id, utf8, len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char c = (char)legacy;
|
||||||
|
sys_tty_write_in(s->tty_id, &c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sys_tty_write_in(s->tty_id, &c, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#include "libc/syscall.h"
|
#include "libc/syscall.h"
|
||||||
#include "libc/libui.h"
|
#include "libc/libui.h"
|
||||||
#include "libc/stdlib.h"
|
#include "libc/stdlib.h"
|
||||||
|
#include "libc/input.h"
|
||||||
|
#include "utf-8.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define COLOR_DARK_PANEL 0xFF202020
|
#define COLOR_DARK_PANEL 0xFF202020
|
||||||
|
|
@ -17,7 +19,6 @@
|
||||||
#define EDITOR_MAX_LINES 128
|
#define EDITOR_MAX_LINES 128
|
||||||
#define EDITOR_MAX_LINE_LEN 256
|
#define EDITOR_MAX_LINE_LEN 256
|
||||||
static int editor_line_height = 16;
|
static int editor_line_height = 16;
|
||||||
static int editor_char_width = 8;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char content[EDITOR_MAX_LINE_LEN];
|
char content[EDITOR_MAX_LINE_LEN];
|
||||||
|
|
@ -176,11 +177,11 @@ static void editor_save_file(void) {
|
||||||
file_modified = 0;
|
file_modified = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void editor_insert_char(char ch) {
|
static void editor_insert_char(int legacy, uint32_t codepoint) {
|
||||||
if (cursor_line >= EDITOR_MAX_LINES) return;
|
if (cursor_line >= EDITOR_MAX_LINES) return;
|
||||||
EditorLine *line = &lines[cursor_line];
|
EditorLine *line = &lines[cursor_line];
|
||||||
|
|
||||||
if (ch == '\n') {
|
if (legacy == '\n') {
|
||||||
if (line_count >= EDITOR_MAX_LINES) return;
|
if (line_count >= EDITOR_MAX_LINES) return;
|
||||||
for (int j = line_count; j > cursor_line; j--) {
|
for (int j = line_count; j > cursor_line; j--) {
|
||||||
lines[j] = lines[j - 1];
|
lines[j] = lines[j - 1];
|
||||||
|
|
@ -206,13 +207,17 @@ static void editor_insert_char(char ch) {
|
||||||
|
|
||||||
cursor_line++;
|
cursor_line++;
|
||||||
cursor_col = 0;
|
cursor_col = 0;
|
||||||
} else if (ch == '\b') {
|
} else if (legacy == KEY_BACKSPACE) {
|
||||||
if (cursor_col > 0) {
|
if (cursor_col > 0) {
|
||||||
for (int i = cursor_col - 1; i < line->length; i++) {
|
const char *prev = text_prev_utf8(line->content, line->content + cursor_col);
|
||||||
line->content[i] = line->content[i + 1];
|
int char_len = (int)((line->content + cursor_col) - prev);
|
||||||
|
|
||||||
|
for (int i = cursor_col - char_len; i < line->length - char_len; i++) {
|
||||||
|
line->content[i] = line->content[i + char_len];
|
||||||
}
|
}
|
||||||
line->length--;
|
line->length -= char_len;
|
||||||
cursor_col--;
|
cursor_col -= char_len;
|
||||||
|
line->content[line->length] = 0;
|
||||||
} else if (cursor_line > 0) {
|
} else if (cursor_line > 0) {
|
||||||
EditorLine *prev = &lines[cursor_line - 1];
|
EditorLine *prev = &lines[cursor_line - 1];
|
||||||
int merge_point = prev->length;
|
int merge_point = prev->length;
|
||||||
|
|
@ -235,14 +240,19 @@ static void editor_insert_char(char ch) {
|
||||||
cursor_col = merge_point;
|
cursor_col = merge_point;
|
||||||
line_count--;
|
line_count--;
|
||||||
}
|
}
|
||||||
} else if (ch >= 32 && ch <= 126) {
|
} else if (codepoint >= 32 && codepoint != 127) {
|
||||||
if (cursor_col < EDITOR_MAX_LINE_LEN - 1) {
|
char utf8[4];
|
||||||
|
int len = text_encode_utf8(codepoint, utf8);
|
||||||
|
if (len > 0 && line->length + len < EDITOR_MAX_LINE_LEN) {
|
||||||
for (int i = line->length; i > cursor_col; i--) {
|
for (int i = line->length; i > cursor_col; i--) {
|
||||||
line->content[i] = line->content[i - 1];
|
line->content[i + len - 1] = line->content[i - 1];
|
||||||
}
|
}
|
||||||
line->content[cursor_col] = ch;
|
for (int i = 0; i < len; i++) {
|
||||||
line->length++;
|
line->content[cursor_col + i] = utf8[i];
|
||||||
cursor_col++;
|
}
|
||||||
|
line->length += len;
|
||||||
|
cursor_col += len;
|
||||||
|
line->content[line->length] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_modified = 1;
|
file_modified = 1;
|
||||||
|
|
@ -386,7 +396,6 @@ static void editor_paint(ui_window_t win) {
|
||||||
int status_y = win_h - footer_h;
|
int status_y = win_h - footer_h;
|
||||||
ui_draw_rounded_rect_filled(win, padding, status_y + 2, content_width, footer_h - 4, 6, COLOR_DARK_PANEL);
|
ui_draw_rounded_rect_filled(win, padding, status_y + 2, content_width, footer_h - 4, 6, COLOR_DARK_PANEL);
|
||||||
|
|
||||||
char status_text[128];
|
|
||||||
ui_draw_string(win, padding + 15, status_y + 5, "Line:", COLOR_DKGRAY);
|
ui_draw_string(win, padding + 15, status_y + 5, "Line:", COLOR_DKGRAY);
|
||||||
|
|
||||||
char line_str[32];
|
char line_str[32];
|
||||||
|
|
@ -409,36 +418,38 @@ static void editor_paint(ui_window_t win) {
|
||||||
ui_draw_string(win, padding + 160, status_y + 5, col_str, COLOR_DARK_TEXT);
|
ui_draw_string(win, padding + 160, status_y + 5, col_str, COLOR_DARK_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void editor_handle_key(char c, bool pressed) {
|
static void editor_handle_key(int legacy, uint32_t codepoint, bool pressed) {
|
||||||
if (!pressed) return;
|
if (!pressed) return;
|
||||||
if (c == 17) { // UP
|
if (legacy == KEY_UP) { // UP
|
||||||
if (cursor_line > 0) {
|
if (cursor_line > 0) {
|
||||||
cursor_line--;
|
cursor_line--;
|
||||||
if (cursor_col > lines[cursor_line].length) cursor_col = lines[cursor_line].length;
|
if (cursor_col > lines[cursor_line].length) cursor_col = lines[cursor_line].length;
|
||||||
if (cursor_line < scroll_top) scroll_top = cursor_line;
|
if (cursor_line < scroll_top) scroll_top = cursor_line;
|
||||||
}
|
}
|
||||||
} else if (c == 18) { // DOWN
|
} else if (legacy == KEY_DOWN) { // DOWN
|
||||||
if (cursor_line < line_count - 1) {
|
if (cursor_line < line_count - 1) {
|
||||||
cursor_line++;
|
cursor_line++;
|
||||||
if (cursor_col > lines[cursor_line].length) cursor_col = lines[cursor_line].length;
|
if (cursor_col > lines[cursor_line].length) cursor_col = lines[cursor_line].length;
|
||||||
editor_ensure_cursor_visible();
|
editor_ensure_cursor_visible();
|
||||||
}
|
}
|
||||||
} else if (c == 19) { // LEFT
|
} else if (legacy == KEY_LEFT) { // LEFT
|
||||||
if (cursor_col > 0) {
|
if (cursor_col > 0) {
|
||||||
cursor_col--;
|
const char *prev = text_prev_utf8(lines[cursor_line].content, lines[cursor_line].content + cursor_col);
|
||||||
|
cursor_col = (int)(prev - lines[cursor_line].content);
|
||||||
} else if (cursor_line > 0) {
|
} else if (cursor_line > 0) {
|
||||||
cursor_line--;
|
cursor_line--;
|
||||||
cursor_col = lines[cursor_line].length;
|
cursor_col = lines[cursor_line].length;
|
||||||
}
|
}
|
||||||
} else if (c == 20) { // RIGHT
|
} else if (legacy == KEY_RIGHT) { // RIGHT
|
||||||
if (cursor_col < lines[cursor_line].length) {
|
if (cursor_col < lines[cursor_line].length) {
|
||||||
cursor_col++;
|
const char *next = text_next_utf8(lines[cursor_line].content + cursor_col);
|
||||||
|
cursor_col = (int)(next - lines[cursor_line].content);
|
||||||
} else if (cursor_line < line_count - 1) {
|
} else if (cursor_line < line_count - 1) {
|
||||||
cursor_line++;
|
cursor_line++;
|
||||||
cursor_col = 0;
|
cursor_col = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
editor_insert_char(c);
|
editor_insert_char(legacy, codepoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -477,11 +488,11 @@ int main(int argc, char **argv) {
|
||||||
editor_paint(win);
|
editor_paint(win);
|
||||||
ui_mark_dirty(win, 0, 0, win_w, win_h);
|
ui_mark_dirty(win, 0, 0, win_w, win_h);
|
||||||
} else if (ev.type == GUI_EVENT_KEY) {
|
} else if (ev.type == GUI_EVENT_KEY) {
|
||||||
editor_handle_key((char)ev.arg1, true);
|
editor_handle_key(ev.arg1, (uint32_t)ev.arg4, true);
|
||||||
editor_paint(win);
|
editor_paint(win);
|
||||||
ui_mark_dirty(win, 0, 0, win_w, win_h);
|
ui_mark_dirty(win, 0, 0, win_w, win_h);
|
||||||
} else if (ev.type == GUI_EVENT_KEYUP) {
|
} else if (ev.type == GUI_EVENT_KEYUP) {
|
||||||
editor_handle_key((char)ev.arg1, false);
|
editor_handle_key(ev.arg1, (uint32_t)ev.arg4, false);
|
||||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue