aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/qreg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/qreg.c')
-rw-r--r--src/qreg.c165
1 files changed, 83 insertions, 82 deletions
diff --git a/src/qreg.c b/src/qreg.c
index 8990210..4cf92f0 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -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
);