diff options
Diffstat (limited to 'src/qreg.c')
-rw-r--r-- | src/qreg.c | 594 |
1 files changed, 321 insertions, 273 deletions
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2023 Robin Haberkorn + * Copyright (C) 2012-2024 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 @@ -18,6 +18,7 @@ #include "config.h" #endif +#include <stdbool.h> #include <string.h> #include <glib.h> @@ -82,7 +83,12 @@ teco_qreg_execute(teco_qreg_t *qreg, teco_qreg_table_t *qreg_table_locals, GErro { g_auto(teco_string_t) macro = {NULL, 0}; - if (!qreg->vtable->get_string(qreg, ¯o.data, ¯o.len, error) || + /* + * SciTECO macros must be in UTF-8, but we don't check the encoding, + * so as not to complicate TECO_ED_DEFAULT_ANSI mode. + * The UTF-8 byte sequences are checked anyway. + */ + if (!qreg->vtable->get_string(qreg, ¯o.data, ¯o.len, NULL, error) || !teco_execute_macro(macro.data, macro.len, qreg_table_locals, error)) { teco_error_add_frame_qreg(qreg->head.name.data, qreg->head.name.len); return FALSE; @@ -120,65 +126,11 @@ teco_qreg_set_eol_mode(teco_qreg_t *qreg, gint mode) if (teco_qreg_current) teco_doc_update(&teco_qreg_current->string, teco_qreg_view); - teco_doc_edit(&qreg->string); + teco_doc_edit(&qreg->string, teco_default_codepage()); teco_view_ssm(teco_qreg_view, SCI_SETEOLMODE, mode, 0); if (teco_qreg_current) - teco_doc_edit(&teco_qreg_current->string); -} - -/** @memberof teco_qreg_t */ -gboolean -teco_qreg_load(teco_qreg_t *qreg, const gchar *filename, GError **error) -{ - if (!qreg->vtable->undo_set_string(qreg, error)) - return FALSE; - - if (teco_qreg_current) - teco_doc_update(&teco_qreg_current->string, teco_qreg_view); - - teco_doc_edit(&qreg->string); - teco_doc_reset(&qreg->string); - - /* - * teco_view_load() might change the EOL style. - */ - teco_qreg_undo_set_eol_mode(qreg); - - /* - * undo_set_string() pushes undo tokens that restore - * the previous document in the view. - * So if loading fails, teco_qreg_current will be - * made the current document again. - */ - if (!teco_view_load(teco_qreg_view, filename, error)) - return FALSE; - - if (teco_qreg_current) - teco_doc_edit(&teco_qreg_current->string); - - return TRUE; -} - -/** @memberof teco_qreg_t */ -gboolean -teco_qreg_save(teco_qreg_t *qreg, const gchar *filename, GError **error) -{ - if (teco_qreg_current) - teco_doc_update(&teco_qreg_current->string, teco_qreg_view); - - teco_doc_edit(&qreg->string); - - if (!teco_view_save(teco_qreg_view, filename, error)) { - if (teco_qreg_current) - teco_doc_edit(&teco_qreg_current->string); - return FALSE; - } - - if (teco_qreg_current) - teco_doc_edit(&teco_qreg_current->string); - - return TRUE; + teco_doc_edit(&teco_qreg_current->string, 0); } static gboolean @@ -204,9 +156,10 @@ teco_qreg_plain_get_integer(teco_qreg_t *qreg, teco_int_t *ret, GError **error) } static gboolean -teco_qreg_plain_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error) +teco_qreg_plain_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, + guint codepage, GError **error) { - teco_doc_set_string(&qreg->string, str, len); + teco_doc_set_string(&qreg->string, str, len, codepage); return TRUE; } @@ -231,43 +184,64 @@ teco_qreg_plain_append_string(teco_qreg_t *qreg, const gchar *str, gsize len, GE if (teco_qreg_current) teco_doc_update(&teco_qreg_current->string, teco_qreg_view); - teco_doc_edit(&qreg->string); + teco_doc_edit(&qreg->string, teco_default_codepage()); teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0); teco_view_ssm(teco_qreg_view, SCI_APPENDTEXT, len, (sptr_t)str); teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0); if (teco_qreg_current) - teco_doc_edit(&teco_qreg_current->string); + teco_doc_edit(&teco_qreg_current->string, 0); return TRUE; } static gboolean -teco_qreg_plain_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, GError **error) +teco_qreg_plain_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, + guint *codepage, GError **error) { - teco_doc_get_string(&qreg->string, str, len); + teco_doc_get_string(&qreg->string, str, len, codepage); return TRUE; } -static gint -teco_qreg_plain_get_character(teco_qreg_t *qreg, guint position, GError **error) +static gboolean +teco_qreg_plain_get_character(teco_qreg_t *qreg, teco_int_t position, + teco_int_t *chr, GError **error) { - gint ret = -1; - if (teco_qreg_current) teco_doc_update(&teco_qreg_current->string, teco_qreg_view); - teco_doc_edit(&qreg->string); + teco_doc_edit(&qreg->string, teco_default_codepage()); - if (position < teco_view_ssm(teco_qreg_view, SCI_GETLENGTH, 0, 0)) - ret = teco_view_ssm(teco_qreg_view, SCI_GETCHARAT, position, 0); - else + 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 %u out of range", position); + "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); + + if (teco_qreg_current) + teco_doc_edit(&teco_qreg_current->string, 0); + + return ret; +} + +static teco_int_t +teco_qreg_plain_get_length(teco_qreg_t *qreg, GError **error) +{ + if (teco_qreg_current) + teco_doc_update(&teco_qreg_current->string, teco_qreg_view); + + teco_doc_edit(&qreg->string, teco_default_codepage()); + + sptr_t len = teco_view_ssm(teco_qreg_view, SCI_GETLENGTH, 0, 0); + teco_int_t ret = teco_view_bytes2glyphs(teco_qreg_view, len); if (teco_qreg_current) - teco_doc_edit(&teco_qreg_current->string); + teco_doc_edit(&teco_qreg_current->string, 0); return ret; } @@ -294,7 +268,7 @@ teco_qreg_plain_edit(teco_qreg_t *qreg, GError **error) if (teco_qreg_current) teco_doc_update(&teco_qreg_current->string, teco_qreg_view); - teco_doc_edit(&qreg->string); + teco_doc_edit(&qreg->string, teco_default_codepage()); teco_interface_show_view(teco_qreg_view); teco_interface_info_update(qreg); @@ -319,6 +293,58 @@ teco_qreg_plain_undo_edit(teco_qreg_t *qreg, GError **error) return TRUE; } +static gboolean +teco_qreg_plain_load(teco_qreg_t *qreg, const gchar *filename, GError **error) +{ + if (!qreg->vtable->undo_set_string(qreg, error)) + return FALSE; + + if (teco_qreg_current) + teco_doc_update(&teco_qreg_current->string, teco_qreg_view); + + teco_doc_edit(&qreg->string, teco_default_codepage()); + teco_doc_reset(&qreg->string); + + /* + * teco_view_load() might change the EOL style. + */ + teco_qreg_undo_set_eol_mode(qreg); + + /* + * undo_set_string() pushes undo tokens that restore + * the previous document in the view. + * So if loading fails, teco_qreg_current will be + * made the current document again. + */ + if (!teco_view_load(teco_qreg_view, filename, error)) + return FALSE; + + if (teco_qreg_current) + teco_doc_edit(&teco_qreg_current->string, 0); + + return TRUE; +} + +static gboolean +teco_qreg_plain_save(teco_qreg_t *qreg, const gchar *filename, GError **error) +{ + if (teco_qreg_current) + teco_doc_update(&teco_qreg_current->string, teco_qreg_view); + + teco_doc_edit(&qreg->string, teco_default_codepage()); + + gboolean ret = teco_view_save(teco_qreg_view, filename, error); + + if (teco_qreg_current) + teco_doc_edit(&teco_qreg_current->string, 0); + + return ret; +} + +/** + * Initializer for vtables of Q-Registers with "plain" storage of strings. + * These store their string part as teco_docs. + */ #define TECO_INIT_QREG(...) { \ .set_integer = teco_qreg_plain_set_integer, \ .undo_set_integer = teco_qreg_plain_undo_set_integer, \ @@ -329,10 +355,13 @@ teco_qreg_plain_undo_edit(teco_qreg_t *qreg, GError **error) .undo_append_string = teco_qreg_plain_undo_set_string, \ .get_string = teco_qreg_plain_get_string, \ .get_character = teco_qreg_plain_get_character, \ + .get_length = teco_qreg_plain_get_length, \ .exchange_string = teco_qreg_plain_exchange_string, \ .undo_exchange_string = teco_qreg_plain_undo_exchange_string, \ .edit = teco_qreg_plain_edit, \ .undo_edit = teco_qreg_plain_undo_edit, \ + .load = teco_qreg_plain_load, \ + .save = teco_qreg_plain_save, \ ##__VA_ARGS__ \ } @@ -345,6 +374,150 @@ teco_qreg_plain_new(const gchar *name, gsize len) return teco_qreg_new(&vtable, name, len); } +static gboolean +teco_qreg_external_edit(teco_qreg_t *qreg, GError **error) +{ + g_auto(teco_string_t) str = {NULL, 0}; + + if (!teco_qreg_plain_edit(qreg, error) || + !qreg->vtable->get_string(qreg, &str.data, &str.len, NULL, error)) + return FALSE; + + teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0); + teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0); + teco_view_ssm(teco_qreg_view, SCI_ADDTEXT, str.len, (sptr_t)str.data); + teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0); + + undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0); + return TRUE; +} + +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}; + guint other_cp, own_cp; + + teco_doc_get_string(src, &other_str.data, &other_str.len, &other_cp); + + if (!qreg->vtable->get_string(qreg, &own_str.data, &own_str.len, &own_cp, error) || + !qreg->vtable->set_string(qreg, other_str.data, other_str.len, other_cp, error)) + return FALSE; + + teco_doc_set_string(src, own_str.data, own_str.len, own_cp); + return TRUE; +} + +static gboolean +teco_qreg_external_undo_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GError **error) +{ + if (!qreg->vtable->undo_set_string(qreg, error)) + return FALSE; + if (qreg->must_undo) // FIXME + teco_doc_undo_set_string(src); + return TRUE; +} + +static gboolean +teco_qreg_external_get_character(teco_qreg_t *qreg, teco_int_t position, + teco_int_t *chr, GError **error) +{ + g_auto(teco_string_t) str = {NULL, 0}; + + if (!qreg->vtable->get_string(qreg, &str.data, &str.len, NULL, error)) + 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; + } + const gchar *p = g_utf8_offset_to_pointer(str.data, position); + + /* + * Make sure that the -1/-2 error values are preserved. + * The sign bit in UCS-4/UTF-32 is unused, so this will even + * suffice if TECO_INTEGER == 32. + */ + *chr = (gint32)g_utf8_get_char_validated(p, -1); + return TRUE; +} + +static teco_int_t +teco_qreg_external_get_length(teco_qreg_t *qreg, GError **error) +{ + g_auto(teco_string_t) str = {NULL, 0}; + + if (!qreg->vtable->get_string(qreg, &str.data, &str.len, NULL, error)) + return -1; + + return g_utf8_strlen(str.data, str.len); +} + +/* + * NOTE: This does not perform EOL normalization unlike teco_view_load(). + * It shouldn't be critical since "external" registers are mainly used for filenames. + * Otherwise we could of course load into the view() and call set_string() afterwards. + */ +static gboolean +teco_qreg_external_load(teco_qreg_t *qreg, const gchar *filename, GError **error) +{ + g_auto(teco_string_t) str = {NULL, 0}; + + return g_file_get_contents(filename, &str.data, &str.len, error) && + qreg->vtable->undo_set_string(qreg, error) && + qreg->vtable->set_string(qreg, str.data, str.len, teco_default_codepage(), error); +} + +/* + * NOTE: This does not simply use g_file_set_contents(), as we have to create + * save point files as well. + * FIXME: On the other hand, this does not set the correct EOL style on the document, + * so teco_view_save() will save only with the default EOL style. + * It might therefore still be a good idea to avoid any conversion. + */ +static gboolean +teco_qreg_external_save(teco_qreg_t *qreg, const gchar *filename, GError **error) +{ + if (teco_qreg_current) + teco_doc_update(&teco_qreg_current->string, teco_qreg_view); + + teco_doc_edit(&qreg->string, teco_default_codepage()); + + g_auto(teco_string_t) str = {NULL, 0}; + if (!qreg->vtable->get_string(qreg, &str.data, &str.len, NULL, error)) + return FALSE; + + teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0); + teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0); + teco_view_ssm(teco_qreg_view, SCI_ADDTEXT, str.len, (sptr_t)str.data); + teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0); + + undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0); + + gboolean ret = teco_view_save(teco_qreg_view, filename, error); + + if (teco_qreg_current) + teco_doc_edit(&teco_qreg_current->string, 0); + + return ret; +} + +/** + * Initializer for vtables of Q-Registers with "external" storage of strings. + * These rely on custom implementations of get_string() and set_string(). + */ +#define TECO_INIT_QREG_EXTERNAL(...) TECO_INIT_QREG( \ + .exchange_string = teco_qreg_external_exchange_string, \ + .undo_exchange_string = teco_qreg_external_undo_exchange_string, \ + .edit = teco_qreg_external_edit, \ + .get_character = teco_qreg_external_get_character, \ + .get_length = teco_qreg_external_get_length, \ + .load = teco_qreg_external_load, \ + .save = teco_qreg_external_save, \ + ##__VA_ARGS__ \ +) + /* * NOTE: The integer-component is currently unused on the "*" special register. */ @@ -368,11 +541,12 @@ teco_qreg_bufferinfo_get_integer(teco_qreg_t *qreg, teco_int_t *ret, GError **er } /* - * FIXME: These operations can and should be implemented. - * Setting the "*" register could for instance rename the file. + * FIXME: Something could be implemented here. There are 2 possibilities: + * Either it renames the current buffer, or opens a file (alternative to EB). */ static gboolean -teco_qreg_bufferinfo_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error) +teco_qreg_bufferinfo_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, + guint codepage, GError **error) { teco_error_qregopunsupported_set(error, qreg->head.name.data, qreg->head.name.len, FALSE); return FALSE; @@ -401,7 +575,8 @@ teco_qreg_bufferinfo_undo_append_string(teco_qreg_t *qreg, GError **error) * NOTE: The `string` component is currently unused on the "*" register. */ static gboolean -teco_qreg_bufferinfo_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, GError **error) +teco_qreg_bufferinfo_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, + guint *codepage, GError **error) { /* * On platforms with a default non-forward-slash directory @@ -416,43 +591,8 @@ teco_qreg_bufferinfo_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, GErr * NOTE: teco_file_normalize_path() does not change the size of the string. */ *len = teco_ring_current->filename ? strlen(teco_ring_current->filename) : 0; - return TRUE; -} - -static gint -teco_qreg_bufferinfo_get_character(teco_qreg_t *qreg, guint position, GError **error) -{ - gsize max_len; - - if (!teco_qreg_bufferinfo_get_string(qreg, NULL, &max_len, error)) - return -1; - - if (position >= max_len) { - g_set_error(error, TECO_ERROR, TECO_ERROR_RANGE, - "Position %u out of range", position); - return -1; - } - - return teco_ring_current->filename[position]; -} - -static gboolean -teco_qreg_bufferinfo_edit(teco_qreg_t *qreg, GError **error) -{ - if (!teco_qreg_plain_edit(qreg, error)) - return FALSE; - - g_auto(teco_string_t) str = {NULL, 0}; - - if (!teco_qreg_bufferinfo_get_string(qreg, &str.data, &str.len, error)) - return FALSE; - - teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0); - teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0); - teco_view_ssm(teco_qreg_view, SCI_ADDTEXT, str.len, (sptr_t)str.data); - teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0); - - undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0); + if (codepage) + *codepage = teco_default_codepage(); return TRUE; } @@ -460,7 +600,7 @@ teco_qreg_bufferinfo_edit(teco_qreg_t *qreg, GError **error) teco_qreg_t * teco_qreg_bufferinfo_new(void) { - static teco_qreg_vtable_t vtable = TECO_INIT_QREG( + static teco_qreg_vtable_t vtable = TECO_INIT_QREG_EXTERNAL( .set_integer = teco_qreg_bufferinfo_set_integer, .undo_set_integer = teco_qreg_bufferinfo_undo_set_integer, .get_integer = teco_qreg_bufferinfo_get_integer, @@ -469,15 +609,22 @@ teco_qreg_bufferinfo_new(void) .append_string = teco_qreg_bufferinfo_append_string, .undo_append_string = teco_qreg_bufferinfo_undo_append_string, .get_string = teco_qreg_bufferinfo_get_string, - .get_character = teco_qreg_bufferinfo_get_character, - .edit = teco_qreg_bufferinfo_edit + /* + * As teco_qreg_bufferinfo_set_string() is not implemented, + * it's important to not inherit teco_qreg_external_exchange_string(). + * `[*` and `]*` will still work though. + * The inherited teco_qreg_external_load() will simply fail. + */ + .exchange_string = teco_qreg_plain_exchange_string, + .undo_exchange_string = teco_qreg_plain_undo_exchange_string ); return teco_qreg_new(&vtable, "*", 1); } static gboolean -teco_qreg_workingdir_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error) +teco_qreg_workingdir_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, + guint codepage, GError **error) { /* * NOTE: Makes sure that `dir` will be null-terminated as str[len] may not be '\0'. @@ -528,7 +675,8 @@ teco_qreg_workingdir_undo_append_string(teco_qreg_t *qreg, GError **error) } static gboolean -teco_qreg_workingdir_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, GError **error) +teco_qreg_workingdir_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, + guint *codepage, GError **error) { /* * On platforms with a default non-forward-slash directory @@ -545,84 +693,22 @@ teco_qreg_workingdir_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, GErr *str = teco_file_normalize_path(dir); else g_free(dir); + if (codepage) + *codepage = teco_default_codepage(); return TRUE; } -static gint -teco_qreg_workingdir_get_character(teco_qreg_t *qreg, guint position, GError **error) -{ - g_auto(teco_string_t) str = {NULL, 0}; - - if (!teco_qreg_workingdir_get_string(qreg, &str.data, &str.len, error)) - return -1; - - if (position >= str.len) { - g_set_error(error, TECO_ERROR, TECO_ERROR_RANGE, - "Position %u out of range", position); - return -1; - } - - return str.data[position]; -} - -static gboolean -teco_qreg_workingdir_edit(teco_qreg_t *qreg, GError **error) -{ - g_auto(teco_string_t) str = {NULL, 0}; - - if (!teco_qreg_plain_edit(qreg, error) || - !teco_qreg_workingdir_get_string(qreg, &str.data, &str.len, error)) - return FALSE; - - teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0); - teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0); - teco_view_ssm(teco_qreg_view, SCI_ADDTEXT, str.len, (sptr_t)str.data); - teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0); - - undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0); - return TRUE; -} - -static gboolean -teco_qreg_workingdir_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GError **error) -{ - g_auto(teco_string_t) other_str, own_str = {NULL, 0}; - - teco_doc_get_string(src, &other_str.data, &other_str.len); - - if (!teco_qreg_workingdir_get_string(qreg, &own_str.data, &own_str.len, error) || - /* FIXME: Why is teco_qreg_plain_set_string() sufficient? */ - !teco_qreg_plain_set_string(qreg, other_str.data, other_str.len, error)) - return FALSE; - - teco_doc_set_string(src, own_str.data, own_str.len); - return TRUE; -} - -static gboolean -teco_qreg_workingdir_undo_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GError **error) -{ - teco_undo_change_dir_to_current(); - if (qreg->must_undo) // FIXME - teco_doc_undo_set_string(src); - return TRUE; -} - /** @static @memberof teco_qreg_t */ teco_qreg_t * teco_qreg_workingdir_new(void) { - static teco_qreg_vtable_t vtable = TECO_INIT_QREG( + 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, .undo_append_string = teco_qreg_workingdir_undo_append_string, - .get_string = teco_qreg_workingdir_get_string, - .get_character = teco_qreg_workingdir_get_character, - .edit = teco_qreg_workingdir_edit, - .exchange_string = teco_qreg_workingdir_exchange_string, - .undo_exchange_string = teco_qreg_workingdir_undo_exchange_string + .get_string = teco_qreg_workingdir_get_string ); /* @@ -639,7 +725,8 @@ teco_qreg_workingdir_new(void) } static gboolean -teco_qreg_clipboard_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error) +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; @@ -724,7 +811,8 @@ teco_qreg_clipboard_undo_set_string(teco_qreg_t *qreg, GError **error) } static gboolean -teco_qreg_clipboard_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, GError **error) +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; @@ -756,93 +844,41 @@ teco_qreg_clipboard_get_string(teco_qreg_t *qreg, gchar **str, gsize *len, GErro else teco_string_clear(&str_converted); *len = str_converted.len; + if (codepage) + *codepage = teco_default_codepage(); return TRUE; } -static gint -teco_qreg_clipboard_get_character(teco_qreg_t *qreg, guint position, GError **error) -{ - g_auto(teco_string_t) str = {NULL, 0}; - - if (!teco_qreg_clipboard_get_string(qreg, &str.data, &str.len, error)) - return -1; - - if (position >= str.len) { - g_set_error(error, TECO_ERROR, TECO_ERROR_RANGE, - "Position %u out of range", position); - return -1; - } - - return str.data[position]; -} - -static gboolean -teco_qreg_clipboard_edit(teco_qreg_t *qreg, GError **error) -{ - if (!teco_qreg_plain_edit(qreg, error)) - return FALSE; - - g_auto(teco_string_t) str = {NULL, 0}; - - if (!teco_qreg_clipboard_get_string(qreg, &str.data, &str.len, error)) - return FALSE; - - teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0); - teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0); - teco_view_ssm(teco_qreg_view, SCI_APPENDTEXT, str.len, (sptr_t)str.data); - teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0); - - undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0); - return TRUE; -} - /* - * FIXME: Very similar to teco_qreg_workingdir_exchange_string(). + * Regardless of whether EOL normalization is enabled, + * this will never perform it. + * Other than that, it's very similar to teco_qreg_external_load(). */ static gboolean -teco_qreg_clipboard_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GError **error) +teco_qreg_clipboard_load(teco_qreg_t *qreg, const gchar *filename, GError **error) { - g_auto(teco_string_t) other_str, own_str = {NULL, 0}; - - teco_doc_get_string(src, &other_str.data, &other_str.len); - - if (!teco_qreg_clipboard_get_string(qreg, &own_str.data, &own_str.len, error) || - /* FIXME: Why is teco_qreg_plain_set_string() sufficient? */ - !teco_qreg_plain_set_string(qreg, other_str.data, other_str.len, error)) - return FALSE; + g_assert(!teco_string_contains(&qreg->head.name, '\0')); + const gchar *clipboard_name = qreg->head.name.data + 1; - teco_doc_set_string(src, own_str.data, own_str.len); - return TRUE; -} + g_auto(teco_string_t) str = {NULL, 0}; -/* - * FIXME: Very similar to teco_qreg_workingdir_undo_exchange_string(). - */ -static gboolean -teco_qreg_clipboard_undo_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GError **error) -{ - if (!teco_qreg_clipboard_undo_set_string(qreg, error)) - return FALSE; - if (qreg->must_undo) // FIXME - teco_doc_undo_set_string(src); - return TRUE; + return g_file_get_contents(filename, &str.data, &str.len, error) && + teco_qreg_clipboard_undo_set_string(qreg, error) && + teco_interface_set_clipboard(clipboard_name, str.data, str.len, error); } /** @static @memberof teco_qreg_t */ teco_qreg_t * teco_qreg_clipboard_new(const gchar *name) { - static teco_qreg_vtable_t vtable = TECO_INIT_QREG( + 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, .undo_append_string = teco_qreg_clipboard_undo_append_string, .get_string = teco_qreg_clipboard_get_string, - .get_character = teco_qreg_clipboard_get_character, - .edit = teco_qreg_clipboard_edit, - .exchange_string = teco_qreg_clipboard_exchange_string, - .undo_exchange_string = teco_qreg_clipboard_undo_exchange_string + .load = teco_qreg_clipboard_load ); teco_qreg_t *qreg = teco_qreg_new(&vtable, "~", 1); @@ -939,7 +975,8 @@ teco_qreg_table_set_environ(teco_qreg_table_t *table, GError **error) qreg = found; } - if (!qreg->vtable->set_string(qreg, value, strlen(value), error)) + if (!qreg->vtable->set_string(qreg, value, strlen(value), + teco_default_codepage(), error)) return FALSE; } @@ -994,7 +1031,7 @@ teco_qreg_table_get_environ(teco_qreg_table_t *table, GError **error) continue; g_auto(teco_string_t) value = {NULL, 0}; - if (!cur->vtable->get_string(cur, &value.data, &value.len, error)) { + if (!cur->vtable->get_string(cur, &value.data, &value.len, NULL, error)) { g_strfreev(envp); return NULL; } @@ -1088,12 +1125,13 @@ teco_qreg_stack_push(teco_qreg_t *qreg, GError **error) { teco_qreg_stack_entry_t entry; g_auto(teco_string_t) string = {NULL, 0}; + guint codepage; if (!qreg->vtable->get_integer(qreg, &entry.integer, error) || - !qreg->vtable->get_string(qreg, &string.data, &string.len, error)) + !qreg->vtable->get_string(qreg, &string.data, &string.len, &codepage, error)) return FALSE; teco_doc_init(&entry.string); - teco_doc_set_string(&entry.string, string.data, string.len); + teco_doc_set_string(&entry.string, string.data, string.len, codepage); teco_doc_update(&entry.string, &qreg->string); /* pass ownership of entry to teco_qreg_stack */ @@ -1196,6 +1234,12 @@ teco_ed_hook(teco_ed_hook_t type, GError **error) if (!teco_qreg_execute(qreg, &locals, error)) goto error_add_frame; + if (teco_qreg_current && !teco_qreg_current->must_undo) { + /* currently editing local Q-Register */ + teco_error_editinglocalqreg_set(error, teco_qreg_current->head.name.data, + teco_qreg_current->head.name.len); + goto error_add_frame; + } return teco_expressions_discard_args(error) && teco_expressions_brace_close(error); @@ -1225,7 +1269,7 @@ struct teco_machine_qregspec_t { union { struct { teco_qreg_type_t type : 8; - gboolean parse_only : 1; + bool parse_only : 1; }; guint __flags; }; @@ -1255,7 +1299,7 @@ TECO_DECLARE_STATE(teco_state_qregspec_secondchar); TECO_DECLARE_STATE(teco_state_qregspec_string); static teco_state_t *teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx, - gchar chr, GError **error); + gunichar chr, GError **error); static teco_state_t * teco_state_qregspec_done(teco_machine_qregspec_t *ctx, GError **error) @@ -1290,7 +1334,7 @@ teco_state_qregspec_done(teco_machine_qregspec_t *ctx, GError **error) } static teco_state_t * -teco_state_qregspec_start_input(teco_machine_qregspec_t *ctx, gchar chr, GError **error) +teco_state_qregspec_start_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error) { /* * FIXME: We're using teco_state_qregspec_start as a success condition, @@ -1307,7 +1351,7 @@ teco_state_qregspec_start_input(teco_machine_qregspec_t *ctx, gchar chr, GError } /* in cmdline.c */ -gboolean teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx, gchar key, GError **error); +gboolean teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error); TECO_DEFINE_STATE(teco_state_qregspec_start, .is_start = TRUE, @@ -1315,7 +1359,7 @@ TECO_DEFINE_STATE(teco_state_qregspec_start, ); static teco_state_t * -teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx, gchar chr, GError **error) +teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error) { /* * FIXME: Disallow space characters? @@ -1334,7 +1378,7 @@ teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx, gchar chr, if (!ctx->parse_only) { if (ctx->parent.must_undo) undo__teco_string_truncate(&ctx->name, ctx->name.len); - teco_string_append_c(&ctx->name, g_ascii_toupper(chr)); + teco_string_append_wc(&ctx->name, g_unichar_toupper(chr)); } return teco_state_qregspec_done(ctx, error); } @@ -1350,7 +1394,7 @@ TECO_DEFINE_STATE(teco_state_qregspec_start_global, ); static teco_state_t * -teco_state_qregspec_firstchar_input(teco_machine_qregspec_t *ctx, gchar chr, GError **error) +teco_state_qregspec_firstchar_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error) { /* * FIXME: Disallow space characters? @@ -1358,7 +1402,7 @@ teco_state_qregspec_firstchar_input(teco_machine_qregspec_t *ctx, gchar chr, GEr if (!ctx->parse_only) { if (ctx->parent.must_undo) undo__teco_string_truncate(&ctx->name, ctx->name.len); - teco_string_append_c(&ctx->name, g_ascii_toupper(chr)); + teco_string_append_wc(&ctx->name, g_unichar_toupper(chr)); } return &teco_state_qregspec_secondchar; } @@ -1368,7 +1412,7 @@ TECO_DEFINE_STATE(teco_state_qregspec_firstchar, ); static teco_state_t * -teco_state_qregspec_secondchar_input(teco_machine_qregspec_t *ctx, gchar chr, GError **error) +teco_state_qregspec_secondchar_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error) { /* * FIXME: Disallow space characters? @@ -1376,7 +1420,7 @@ teco_state_qregspec_secondchar_input(teco_machine_qregspec_t *ctx, gchar chr, GE if (!ctx->parse_only) { if (ctx->parent.must_undo) undo__teco_string_truncate(&ctx->name, ctx->name.len); - teco_string_append_c(&ctx->name, g_ascii_toupper(chr)); + teco_string_append_wc(&ctx->name, g_unichar_toupper(chr)); } return teco_state_qregspec_done(ctx, error); } @@ -1386,7 +1430,7 @@ TECO_DEFINE_STATE(teco_state_qregspec_secondchar, ); static teco_state_t * -teco_state_qregspec_string_input(teco_machine_qregspec_t *ctx, gchar chr, GError **error) +teco_state_qregspec_string_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error) { /* * Makes sure that braces within string building constructs do not have to be @@ -1427,7 +1471,7 @@ teco_state_qregspec_string_input(teco_machine_qregspec_t *ctx, gchar chr, GError /* in cmdline.c */ gboolean teco_state_qregspec_string_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx, - gchar key, GError **error); + gunichar key, GError **error); TECO_DEFINE_STATE(teco_state_qregspec_string, .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_string_process_edit_cmd @@ -1488,7 +1532,7 @@ teco_machine_qregspec_get_stringbuilding(teco_machine_qregspec_t *ctx) * @memberof teco_machine_qregspec_t */ teco_machine_qregspec_status_t -teco_machine_qregspec_input(teco_machine_qregspec_t *ctx, gchar chr, +teco_machine_qregspec_input(teco_machine_qregspec_t *ctx, gunichar chr, teco_qreg_t **result, teco_qreg_table_t **result_table, GError **error) { ctx->parse_only = result == NULL; @@ -1516,7 +1560,7 @@ teco_machine_qregspec_get_results(teco_machine_qregspec_t *ctx, gboolean teco_machine_qregspec_auto_complete(teco_machine_qregspec_t *ctx, teco_string_t *insert) { - gsize restrict_len = 0; + guint restrict_len = 0; /* * NOTE: We could have separate process_edit_cmd_cb() for @@ -1531,6 +1575,10 @@ teco_machine_qregspec_auto_complete(teco_machine_qregspec_t *ctx, teco_string_t /* two-letter Q-Reg */ restrict_len = 2; + /* + * FIXME: This is not quite right as it will propose even + * lower case single or two-letter Q-Register names. + */ return teco_rb3str_auto_complete(&ctx->result_table->tree, !restrict_len, ctx->name.data, ctx->name.len, restrict_len, insert) && ctx->nesting == 1; |