diff options
Diffstat (limited to 'src/qreg.c')
| -rw-r--r-- | src/qreg.c | 165 |
1 files changed, 83 insertions, 82 deletions
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2025 Robin Haberkorn + * Copyright (C) 2012-2026 Robin Haberkorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,6 +39,7 @@ #include "ring.h" #include "eol.h" #include "error.h" +#include "rb3str.h" #include "qreg.h" /** @@ -239,18 +240,12 @@ teco_qreg_plain_get_character(teco_qreg_t *qreg, teco_int_t position, sptr_t len = teco_view_ssm(teco_qreg_view, SCI_GETLENGTH, 0, 0); gssize off = teco_view_glyphs2bytes(teco_qreg_view, position); - gboolean ret = off >= 0 && off != len; - if (!ret) - g_set_error(error, TECO_ERROR, TECO_ERROR_RANGE, - "Position %" TECO_INT_FORMAT " out of range", position); - /* make sure we still restore the current Q-Register */ - else - *chr = teco_view_get_character(teco_qreg_view, off, len); + *chr = off >= 0 && off != len ? teco_view_get_character(teco_qreg_view, off, len) : -1; if (teco_qreg_current) teco_doc_edit(&teco_qreg_current->string, 0); - return ret; + return TRUE; } static teco_int_t @@ -340,7 +335,7 @@ teco_qreg_plain_load(teco_qreg_t *qreg, const gchar *filename, GError **error) * So if loading fails, teco_qreg_current will be * made the current document again. */ - if (!teco_view_load(teco_qreg_view, filename, error)) + if (!teco_view_load(teco_qreg_view, filename, TRUE, error)) return FALSE; if (teco_qreg_current) @@ -492,6 +487,19 @@ teco_qreg_external_edit(teco_qreg_t *qreg, GError **error) } static gboolean +teco_qreg_external_append_string(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error) +{ + g_auto(teco_string_t) buf = {NULL, 0}; + guint codepage; + + if (!qreg->vtable->undo_set_string(qreg, error) || + !qreg->vtable->get_string(qreg, &buf.data, &buf.len, &codepage, error)) + return FALSE; + teco_string_append(&buf, str, len); + return qreg->vtable->set_string(qreg, buf.data, buf.len, codepage, error); +} + +static gboolean teco_qreg_external_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GError **error) { g_auto(teco_string_t) other_str, own_str = {NULL, 0}; @@ -527,9 +535,8 @@ teco_qreg_external_get_character(teco_qreg_t *qreg, teco_int_t position, return FALSE; if (position < 0 || position >= g_utf8_strlen(str.data, str.len)) { - g_set_error(error, TECO_ERROR, TECO_ERROR_RANGE, - "Position %" TECO_INT_FORMAT " out of range", position); - return FALSE; + *chr = -1; + return TRUE; } const gchar *p = g_utf8_offset_to_pointer(str.data, position); @@ -610,6 +617,7 @@ teco_qreg_external_save(teco_qreg_t *qreg, const gchar *filename, GError **error .exchange_string = teco_qreg_external_exchange_string, \ .undo_exchange_string = teco_qreg_external_undo_exchange_string, \ .edit = teco_qreg_external_edit, \ + .append_string = teco_qreg_external_append_string, \ .get_character = teco_qreg_external_get_character, \ .get_length = teco_qreg_external_get_length, \ .load = teco_qreg_external_load, \ @@ -642,6 +650,8 @@ teco_qreg_bufferinfo_get_integer(teco_qreg_t *qreg, teco_int_t *ret, GError **er /* * FIXME: Something could be implemented here. There are 2 possibilities: * Either it renames the current buffer, or opens a file (alternative to EB). + * Should we implement it, we can probably remove the append_string + * implementation below. */ static gboolean teco_qreg_bufferinfo_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, @@ -722,7 +732,7 @@ teco_qreg_workingdir_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, g_auto(teco_string_t) dir; teco_string_init(&dir, str, len); - if (teco_string_contains(&dir, '\0')) { + if (teco_string_contains(dir, '\0')) { g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, "Directory contains null-character"); return FALSE; @@ -747,17 +757,6 @@ teco_qreg_workingdir_undo_set_string(teco_qreg_t *qreg, GError **error) return TRUE; } -/* - * FIXME: Redundant with teco_qreg_bufferinfo_append_string()... - * Best solution would be to simply implement them. - */ -static gboolean -teco_qreg_workingdir_append_string(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error) -{ - teco_error_qregopunsupported_set(error, qreg->head.name.data, qreg->head.name.len, FALSE); - return FALSE; -} - static gboolean teco_qreg_workingdir_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, guint *codepage, GError **error) @@ -791,7 +790,6 @@ teco_qreg_workingdir_new(void) static teco_qreg_vtable_t vtable = TECO_INIT_QREG_EXTERNAL( .set_string = teco_qreg_workingdir_set_string, .undo_set_string = teco_qreg_workingdir_undo_set_string, - .append_string = teco_qreg_workingdir_append_string, .get_string = teco_qreg_workingdir_get_string ); @@ -801,19 +799,27 @@ teco_qreg_workingdir_new(void) * the "\e" register also exists. * Not to mention that environment variable regs also start with dollar. * Perhaps "~" would be a better choice, although it is also already used? - * Most logical would be ".", but this should probably map to to Dot and - * is also ugly to write in practice. + * Most logical would be ".", but it is also ugly to write in practice. * Perhaps "@"... */ return teco_qreg_new(&vtable, "$", 1); } +static inline const gchar * +teco_qreg_clipboard_get_name(const teco_qreg_t *qreg) +{ + g_assert(1 <= qreg->head.name.len && qreg->head.name.len <= 2 && + *qreg->head.name.data == '~'); + if (qreg->head.name.len > 1) + return qreg->head.name.data+1; + return teco_ed & TECO_ED_CLIP_PRIMARY ? "P" : "C"; +} + static gboolean teco_qreg_clipboard_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, guint codepage, GError **error) { - g_assert(!teco_string_contains(&qreg->head.name, '\0')); - const gchar *clipboard_name = qreg->head.name.data + 1; + const gchar *clipboard_name = teco_qreg_clipboard_get_name(qreg); if (teco_ed & TECO_ED_AUTOEOL) { /* @@ -849,17 +855,6 @@ teco_qreg_clipboard_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, return TRUE; } -/* - * FIXME: Redundant with teco_qreg_bufferinfo_append_string()... - * Best solution would be to simply implement them. - */ -static gboolean -teco_qreg_clipboard_append_string(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error) -{ - teco_error_qregopunsupported_set(error, qreg->head.name.data, qreg->head.name.len, FALSE); - return FALSE; -} - static gboolean teco_qreg_clipboard_undo_set_string(teco_qreg_t *qreg, GError **error) { @@ -873,8 +868,7 @@ teco_qreg_clipboard_undo_set_string(teco_qreg_t *qreg, GError **error) if (!teco_undo_enabled) return TRUE; - g_assert(!teco_string_contains(&qreg->head.name, '\0')); - const gchar *clipboard_name = qreg->head.name.data + 1; + const gchar *clipboard_name = teco_qreg_clipboard_get_name(qreg); /* * Ownership of str is passed to the undo token. @@ -892,8 +886,7 @@ static gboolean teco_qreg_clipboard_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, guint *codepage, GError **error) { - g_assert(!teco_string_contains(&qreg->head.name, '\0')); - const gchar *clipboard_name = qreg->head.name.data + 1; + const gchar *clipboard_name = teco_qreg_clipboard_get_name(qreg); if (!(teco_ed & TECO_ED_AUTOEOL)) /* @@ -937,8 +930,7 @@ teco_qreg_clipboard_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, static gboolean teco_qreg_clipboard_load(teco_qreg_t *qreg, const gchar *filename, GError **error) { - g_assert(!teco_string_contains(&qreg->head.name, '\0')); - const gchar *clipboard_name = qreg->head.name.data + 1; + const gchar *clipboard_name = teco_qreg_clipboard_get_name(qreg); g_auto(teco_string_t) str = {NULL, 0}; @@ -954,13 +946,18 @@ teco_qreg_clipboard_new(const gchar *name) static teco_qreg_vtable_t vtable = TECO_INIT_QREG_EXTERNAL( .set_string = teco_qreg_clipboard_set_string, .undo_set_string = teco_qreg_clipboard_undo_set_string, - .append_string = teco_qreg_clipboard_append_string, .get_string = teco_qreg_clipboard_get_string, .load = teco_qreg_clipboard_load ); teco_qreg_t *qreg = teco_qreg_new(&vtable, "~", 1); teco_string_append(&qreg->head.name, name, strlen(name)); + /* + * Register "~" is the default clipboard, which defaults to "~C". + * This is configurable via the integer cell. + */ + if (qreg->head.name.len == 1) + qreg->integer = 'C'; return qreg; } @@ -974,9 +971,9 @@ teco_qreg_table_init(teco_qreg_table_t *table, gboolean must_undo) /* general purpose registers */ for (gchar q = 'A'; q <= 'Z'; q++) - teco_qreg_table_insert(table, teco_qreg_plain_new(&q, sizeof(q))); + teco_qreg_table_insert_unique(table, teco_qreg_plain_new(&q, sizeof(q))); for (gchar q = '0'; q <= '9'; q++) - teco_qreg_table_insert(table, teco_qreg_plain_new(&q, sizeof(q))); + teco_qreg_table_insert_unique(table, teco_qreg_plain_new(&q, sizeof(q))); } /** @memberof teco_qreg_table_t */ @@ -986,10 +983,10 @@ teco_qreg_table_init_locals(teco_qreg_table_t *table, gboolean must_undo) teco_qreg_table_init(table, must_undo); /* search mode ("^X") */ - teco_qreg_table_insert(table, teco_qreg_plain_new("\x18", 1)); + teco_qreg_table_insert_unique(table, teco_qreg_plain_new("\x18", 1)); /* numeric radix ("^R") */ table->radix = teco_qreg_radix_new(); - teco_qreg_table_insert(table, table->radix); + teco_qreg_table_insert_unique(table, table->radix); } static inline void @@ -1110,7 +1107,7 @@ teco_qreg_table_get_environ(teco_qreg_table_t *table, GError **error) for (teco_qreg_t *cur = first; cur && cur->head.name.data[0] == '$'; cur = (teco_qreg_t *)teco_rb3str_get_next(&cur->head)) { - const teco_string_t *name = &cur->head.name; + const teco_string_t name = cur->head.name; /* * Ignore the "$" register (not an environment @@ -1118,7 +1115,7 @@ teco_qreg_table_get_environ(teco_qreg_table_t *table, GError **error) * name contains "=" or null (not allowed in environment * variable names). */ - if (name->len == 1 || + if (name.len == 1 || teco_string_contains(name, '=') || teco_string_contains(name, '\0')) continue; @@ -1127,16 +1124,16 @@ teco_qreg_table_get_environ(teco_qreg_table_t *table, GError **error) g_strfreev(envp); return NULL; } - if (teco_string_contains(&value, '\0')) { + if (teco_string_contains(value, '\0')) { g_strfreev(envp); g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED, "Environment register \"%s\" must not contain null characters", - name->data); + name.data); return NULL; } /* more efficient than g_environ_setenv() */ - *p++ = g_strconcat(name->data+1, "=", value.data, NULL); + *p++ = g_strconcat(name.data+1, "=", value.data, NULL); } *p = NULL; @@ -1336,16 +1333,16 @@ teco_ed_hook(teco_ed_hook_t type, GError **error) return teco_expressions_discard_args(error) && teco_expressions_brace_close(error); - static const gchar *type2name[] = { - [TECO_ED_HOOK_ADD-1] = "ADD", - [TECO_ED_HOOK_EDIT-1] = "EDIT", - [TECO_ED_HOOK_CLOSE-1] = "CLOSE", - [TECO_ED_HOOK_QUIT-1] = "QUIT" + static const gchar *const type2name[] = { + [TECO_ED_HOOK_ADD] = "ADD", + [TECO_ED_HOOK_EDIT] = "EDIT", + [TECO_ED_HOOK_CLOSE] = "CLOSE", + [TECO_ED_HOOK_QUIT] = "QUIT" }; error_add_frame: - g_assert(0 <= type-1 && type-1 < G_N_ELEMENTS(type2name)); - teco_error_add_frame_edhook(type2name[type-1]); + g_assert(0 <= type && type < G_N_ELEMENTS(type2name)); + teco_error_add_frame_edhook(type2name[type]); return FALSE; } @@ -1380,15 +1377,12 @@ TECO_DEFINE_UNDO_SCALAR(teco_machine_qregspec_flags_t); #define teco_undo_qregspec_flags(VAR) \ (*teco_undo_object_teco_machine_qregspec_flags_t_push(&(VAR))) -/* - * FIXME: All teco_state_qregspec_* states could be static? - */ -TECO_DECLARE_STATE(teco_state_qregspec_start); -TECO_DECLARE_STATE(teco_state_qregspec_start_global); -TECO_DECLARE_STATE(teco_state_qregspec_caret); -TECO_DECLARE_STATE(teco_state_qregspec_firstchar); -TECO_DECLARE_STATE(teco_state_qregspec_secondchar); -TECO_DECLARE_STATE(teco_state_qregspec_string); +static teco_state_t teco_state_qregspec_start; +static teco_state_t teco_state_qregspec_start_global; +static teco_state_t teco_state_qregspec_caret; +static teco_state_t teco_state_qregspec_firstchar; +static teco_state_t teco_state_qregspec_secondchar; +static teco_state_t teco_state_qregspec_string; static teco_state_t *teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error); @@ -1416,7 +1410,7 @@ teco_state_qregspec_done(teco_machine_qregspec_t *ctx, GError **error) case TECO_QREG_OPTIONAL_INIT: if (!ctx->result) { ctx->result = teco_qreg_plain_new(ctx->name.data, ctx->name.len); - teco_qreg_table_insert(ctx->result_table, ctx->result); + teco_qreg_table_insert_unique(ctx->result_table, ctx->result); teco_qreg_table_undo_remove(ctx->result); } break; @@ -1445,11 +1439,12 @@ teco_state_qregspec_start_input(teco_machine_qregspec_t *ctx, gunichar chr, GErr /* in cmdline.c */ gboolean teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error); -gboolean teco_state_qregspec_insert_completion(teco_machine_qregspec_t *ctx, const teco_string_t *str, +gboolean teco_state_qregspec_insert_completion(teco_machine_qregspec_t *ctx, teco_string_t str, GError **error); -TECO_DEFINE_STATE(teco_state_qregspec_start, +static TECO_DEFINE_STATE(teco_state_qregspec_start, .is_start = TRUE, + .input_cb = (teco_state_input_cb_t)teco_state_qregspec_start_input, .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd, .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_qregspec_insert_completion ); @@ -1485,7 +1480,8 @@ teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx, gunichar ch * Alternatively, we'd have to introduce a teco_machine_qregspec_t::status attribute. * Or even better, why not use special pointers like ((teco_state_t *)"teco_state_qregspec_done")? */ -TECO_DEFINE_STATE(teco_state_qregspec_start_global, +static TECO_DEFINE_STATE(teco_state_qregspec_start_global, + .input_cb = (teco_state_input_cb_t)teco_state_qregspec_start_global_input, .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd ); @@ -1506,7 +1502,9 @@ teco_state_qregspec_caret_input(teco_machine_qregspec_t *ctx, gunichar chr, GErr return teco_state_qregspec_done(ctx, error); } -TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_qregspec_caret); +static TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_qregspec_caret, + .input_cb = (teco_state_input_cb_t)teco_state_qregspec_caret_input +); static teco_state_t * teco_state_qregspec_firstchar_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error) @@ -1522,7 +1520,8 @@ teco_state_qregspec_firstchar_input(teco_machine_qregspec_t *ctx, gunichar chr, return &teco_state_qregspec_secondchar; } -TECO_DEFINE_STATE(teco_state_qregspec_firstchar, +static TECO_DEFINE_STATE(teco_state_qregspec_firstchar, + .input_cb = (teco_state_input_cb_t)teco_state_qregspec_firstchar_input, .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd ); @@ -1540,7 +1539,8 @@ teco_state_qregspec_secondchar_input(teco_machine_qregspec_t *ctx, gunichar chr, return teco_state_qregspec_done(ctx, error); } -TECO_DEFINE_STATE(teco_state_qregspec_secondchar, +static TECO_DEFINE_STATE(teco_state_qregspec_secondchar, + .input_cb = (teco_state_input_cb_t)teco_state_qregspec_secondchar_input, .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd ); @@ -1587,10 +1587,11 @@ teco_state_qregspec_string_input(teco_machine_qregspec_t *ctx, gunichar chr, GEr /* in cmdline.c */ gboolean teco_state_qregspec_string_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error); -gboolean teco_state_qregspec_string_insert_completion(teco_machine_qregspec_t *ctx, const teco_string_t *str, +gboolean teco_state_qregspec_string_insert_completion(teco_machine_qregspec_t *ctx, teco_string_t str, GError **error); -TECO_DEFINE_STATE(teco_state_qregspec_string, +static TECO_DEFINE_STATE(teco_state_qregspec_string, + .input_cb = (teco_state_input_cb_t)teco_state_qregspec_string_input, .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_string_process_edit_cmd, .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_qregspec_string_insert_completion ); |
