From daded0017161fd907f08bfc016e62643b07c1afb Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Tue, 21 Jul 2026 18:13:02 +0300 Subject: [PATCH] text edit: text navigation. --- src/utils/d_array.c | 29 +++++++++++-- src/utils/d_array.h | 2 +- src/utils/utf8.c | 21 ++++++++- src/utils/utf8.h | 1 + src/widget/input.c | 16 +------ src/windows/text_edit.c | 96 +++++++++++++++++++++++++++++------------ src/windows/text_edit.h | 19 +++----- 7 files changed, 123 insertions(+), 61 deletions(-) diff --git a/src/utils/d_array.c b/src/utils/d_array.c index c4fea46..961482d 100644 --- a/src/utils/d_array.c +++ b/src/utils/d_array.c @@ -21,13 +21,36 @@ void u_d_arr_ptr_add(d_array_ptr_t *arr, void *ptr, int32_t idx) { if (idx > arr->capacity - 1) { int32_t new_capacity = idx * 2; arr->arr = realloc(arr->arr, new_capacity); - memset(arr->arr+arr->capacity, 0, arr->capacity - new_capacity); + memset(arr->arr + arr->capacity, 0, arr->capacity - new_capacity); arr->capacity = new_capacity; } - if (arr->fist_el == NULL) arr->fist_el = ptr; + if (arr->fist_el == NULL) + arr->fist_el = ptr; arr->last_el = ptr; arr->arr[idx] = ptr; - arr->length = idx+1; + arr->length = idx + 1; +} + +void u_d_arr_ptr_remove_cb(d_array_ptr_t *arr, void *ptr, int32_t idx, + u_d_arr_free_callback *callback) { + void *_ptr = NULL; + int _idx = idx; + + if (idx > 0) { + _ptr = arr->arr[idx]; + } else if (ptr != NULL) { + for (int i = 0; i < arr->length; i++) { + if (arr->arr[i] == ptr) { + _ptr = arr->arr[i]; + _idx = i; + } + } + } + + callback(_ptr); + arr->arr[_idx] = NULL; + arr->length--; + memmove(arr->arr[_idx], arr->arr[_idx+1], arr->length - _idx); } void u_d_arr_ptr_free(d_array_ptr_t *arr) { diff --git a/src/utils/d_array.h b/src/utils/d_array.h index 93c699c..73369fd 100644 --- a/src/utils/d_array.h +++ b/src/utils/d_array.h @@ -13,7 +13,7 @@ typedef struct d_array_ptr_t { void *last_el; } d_array_ptr_t; -typedef void *u_d_arr_free_callback(void *arg); +typedef void u_d_arr_free_callback(void *arg); void u_d_arr_ptr_init(d_array_ptr_t *arr, int32_t init_capacity); void u_d_arr_ptr_add(d_array_ptr_t *arr, void *ptr, int32_t idx); diff --git a/src/utils/utf8.c b/src/utils/utf8.c index d4aa37f..e2adf28 100644 --- a/src/utils/utf8.c +++ b/src/utils/utf8.c @@ -55,9 +55,9 @@ int32_t u_utf8_curs_printw(WINDOW *win, int32_t *y, int32_t *x, if (multiline) { _y++; - for (int i = 1; max_len*i < nsize; i++) { + for (int i = 1; max_len * i < nsize; i++) { _x = *x; - mvwaddnwstr(win, _y++, _x, wline + max_len*i, max_len); + mvwaddnwstr(win, _y++, _x, wline + max_len * i, max_len); } } @@ -67,3 +67,20 @@ int32_t u_utf8_curs_printw(WINDOW *win, int32_t *y, int32_t *x, free(wline); return nsize; } + +wchar_t u_utf8_get_full_letter(int key, WINDOW *win) { + char long_key[3]; + int short_val_len = 1; + wchar_t wkey; + long_key[0] = key; + if ((key & 0xC0) == 0xC0) { + long_key[1] = wgetch(win); + long_key[2] = '\0'; + short_val_len++; + } else { + long_key[1] = '\0'; + } + mbstowcs(&wkey, (const char *)&long_key, 2); + + return wkey; +} \ No newline at end of file diff --git a/src/utils/utf8.h b/src/utils/utf8.h index d81ae68..4116612 100644 --- a/src/utils/utf8.h +++ b/src/utils/utf8.h @@ -10,5 +10,6 @@ size_t u_utf8_code_points_count(const char *s); int32_t u_utf8_convert_to_wide(const char *utf8_str, wchar_t **restrict wide_str, size_t *restrict o_len); int32_t u_utf8_curs_printw(WINDOW *win, int32_t *y, int32_t *x, const char* utf8_str, int max_len, bool multiline); +wchar_t u_utf8_get_full_letter(int key, WINDOW *win); #endif \ No newline at end of file diff --git a/src/widget/input.c b/src/widget/input.c index 586fa49..38c9f84 100644 --- a/src/widget/input.c +++ b/src/widget/input.c @@ -16,10 +16,7 @@ bool w_input_default_key_action(w_cb_args_t *args) { w_g_el_t *g_el = args->active_el; w_input_t *input = g_el->element; int32_t start_pos = 0; - wchar_t w_key[2]; app_t *app = args->app; - char long_key[3]; - int short_val_len = 1; switch (key) { case KEY_BACKSPACE: @@ -47,23 +44,14 @@ bool w_input_default_key_action(w_cb_args_t *args) { default: if (input->value_len == input->max_len) break; - long_key[0] = key; - input->value_len++; - if ((key & 0xC0) == 0xC0) { - long_key[1] = wgetch(app->win); - long_key[2] = '\0'; - short_val_len++; - } else { - long_key[1] = '\0'; - } - mbstowcs(w_key, (const char *)&long_key, 2); + key = u_utf8_get_full_letter(key, app->win); if (input->cur_pos > 0) { start_pos = input->value_len - input->cur_pos - 1; memmove(input->w_value + start_pos + 1, input->w_value + start_pos, sizeof(wchar_t) * (input->value_len - start_pos)); input->w_value[start_pos] = key; } else { - input->w_value[input->value_len - 1] = w_key[0]; + input->w_value[input->value_len - 1] = key; input->w_value[input->value_len] = '\0'; } break; diff --git a/src/windows/text_edit.c b/src/windows/text_edit.c index 8ef1645..c2b8164 100644 --- a/src/windows/text_edit.c +++ b/src/windows/text_edit.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -16,12 +17,14 @@ #include "text_edit.h" #include "widget_core.h" -/* TODO: create dynamic array of endline positions */ +/* TODO: расширять capacity линии при достижении лимита */ +/* TODO: нижняя панель-индикатор */ -/* - Массив d_array, состоящие из элементов, описывающий строки. - В строках записывать: длину, номер строки. -*/ +static void line_destroy_cb(void *line_arg) { + w_te_ui_line_t *line = line_arg; + free(line->text); + free(line); +} static void w_te_cb(w_cb_args_t *args) { app_t *app = args->app; @@ -32,15 +35,46 @@ static void w_te_cb(w_cb_args_t *args) { switch (key) { case KEY_BACKSPACE: case KEY_DL: - fui->current_line->text[fui->current_line->len--] = 0; + if (fui->cur_line->len > 0) { + if (fui->cur_line_pos == fui->cur_line->len) { + fui->cur_line->text[--fui->cur_line_pos] = 0; + } else { + int n = fui->cur_line->len - fui->cur_line_pos + 1; + memmove(fui->cur_line->text + fui->cur_line_pos - 1, + fui->cur_line->text + fui->cur_line_pos, n * sizeof(wchar_t)); + fui->cur_line_pos--; + } + fui->cur_line->len--; + } else { + if (fui->cur_line_idx > 0) { + u_d_arr_ptr_remove_cb(&(fui->lines_arr), fui->cur_line, + fui->cur_line_idx, &line_destroy_cb); + fui->cur_line = fui->lines_arr.arr[--fui->cur_line_idx]; + fui->cur_line_pos = fui->cur_line->len; + } + } break; case KEY_UP: - fui->cur_shift_pos.y--; - wchar_t *nl_ptr = NULL; - wchar_t *line_start = fui->line; + if (fui->cur_line_idx > 0) { + fui->cur_line = fui->lines_arr.arr[--fui->cur_line_idx]; + fui->cur_line_pos = fui->cur_line->len; + } break; case KEY_DOWN: - fui->cur_shift_pos.y++; + if (fui->lines_arr.arr[fui->cur_line_idx + 1] != NULL) { + fui->cur_line = fui->lines_arr.arr[++fui->cur_line_idx]; + fui->cur_line_pos = fui->cur_line->len; + } + break; + case KEY_LEFT: + if (fui->cur_line_pos > 0) { + fui->cur_line_pos--; + } + break; + case KEY_RIGHT: + if (fui->cur_line_pos < fui->cur_line->len) { + fui->cur_line_pos++; + } break; case '\n': new_line = malloc(sizeof(w_te_ui_line_t)); @@ -48,13 +82,23 @@ static void w_te_cb(w_cb_args_t *args) { new_line->capacity = new_line->len = INBUFSIZE; new_line->text[0] = 0; new_line->len = 0; - u_d_array_append(&(fui->lines_arr), new_line, sizeof(w_te_ui_line_t)); - fui->current_line = new_line; + fui->cur_line = new_line; + fui->cur_line_idx++; + fui->cur_line_pos = 0; break; default: - fui->current_line->text[fui->current_line->len++] = key; - fui->current_line->text[fui->current_line->len] = 0; + key = u_utf8_get_full_letter(key, app->win); + if (fui->cur_line_pos == fui->cur_line->len) { + fui->cur_line->text[fui->cur_line_pos++] = key; + fui->cur_line->text[fui->cur_line_pos] = 0; + } else { + int n = fui->cur_line->len - fui->cur_line_pos + 1; + memmove(fui->cur_line->text + fui->cur_line_pos + 1, + fui->cur_line->text + fui->cur_line_pos, n * sizeof(wchar_t)); + fui->cur_line->text[fui->cur_line_pos++] = key; + } + fui->cur_line->len++; } } @@ -127,19 +171,16 @@ w_te_ui_t *w_te_init_win(app_t *app) { wcsncpy(app->top_text, top_text, top_text_len); app->top_text[top_text_len] = 0; u_d_arr_ptr_init(&(fui->lines_arr), INBUFSIZE); - fui->current_line = malloc(sizeof(w_te_ui_line_t)); - fui->current_line->text = malloc(INBUFSIZE * sizeof(wchar_t)); - fui->current_line->len = 0; - fui->current_line->capacity = INBUFSIZE; - u_d_array_append(&(fui->lines_arr), fui->current_line, sizeof(w_te_ui_line_t)); + fui->cur_line = malloc(sizeof(w_te_ui_line_t)); + fui->cur_line->text = malloc(INBUFSIZE * sizeof(wchar_t)); + fui->cur_line->len = 0; + fui->cur_line->capacity = INBUFSIZE; + u_d_array_append(&(fui->lines_arr), fui->cur_line, sizeof(w_te_ui_line_t)); + fui->cur_line_idx = 0; return fui; } -void w_te_reset(w_te_ui_t *fui) { - fui->line[0] = 0; - fui->cur_shift_pos.x = 0; - fui->cur_shift_pos.y = 0; -} +void w_te_reset(w_te_ui_t *fui) { fui->cur_line_pos = 0; } void w_te_reset_app(void *app) { app_t *_app = app; @@ -165,8 +206,6 @@ void w_te_draw(w_te_ui_t *fui) { mvwprintw(win, p_y + i, p_x, "%*s", fui->w.sz.x, ""); } - wchar_t *cur_ptr = fui->line; - wchar_t *nl_ptr = wcschr(cur_ptr, '\n'); w_te_ui_line_t *line_arr_el = NULL; if (fui->lines_arr.length > 0) { @@ -176,8 +215,9 @@ void w_te_draw(w_te_ui_t *fui) { } } - fui->cur_abs_pos.y = p_y; - fui->cur_abs_pos.x = p_x; + p_y--; + + wmove(win, fui->cur_line_idx, fui->cur_line_pos); p_x = 1; diff --git a/src/windows/text_edit.h b/src/windows/text_edit.h index a47729e..218c5a2 100644 --- a/src/windows/text_edit.h +++ b/src/windows/text_edit.h @@ -21,19 +21,11 @@ typedef struct { typedef struct { w_t w; - WINDOW *win; - wchar_t line[INBUFSIZE * 10]; - int line_cur_pos; - struct { - int x; - int y; - } cur_shift_pos; - struct { - int x; - int y; - } cur_abs_pos; - p_file_t *file_ptr; - w_te_ui_line_t *current_line; + WINDOW *win; + p_file_t *file_ptr; + w_te_ui_line_t *cur_line; + int cur_line_idx; + int cur_line_pos; d_array_ptr_t lines_arr; } w_te_ui_t; @@ -42,5 +34,6 @@ void w_te_destroy(w_te_ui_t **fui); void w_te_reset(w_te_ui_t *fl_ui); w_te_ui_t *w_te_init(WINDOW **win, w_t *w_parent); w_te_ui_t *w_te_init_win(app_t *app); +void u_d_arr_ptr_remove_cb(d_array_ptr_t *arr, void *ptr, int32_t idx, u_d_arr_free_callback *callback); #endif \ No newline at end of file