aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/qreg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/qreg.c')
-rw-r--r--src/qreg.c594
1 files changed, 321 insertions, 273 deletions
diff --git a/src/qreg.c b/src/qreg.c
index 14cd331..c337dbe 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -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, &macro.data, &macro.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, &macro.data, &macro.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;