aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/qreg.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qreg.h')
-rw-r--r--src/qreg.h238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/qreg.h b/src/qreg.h
new file mode 100644
index 0000000..4797a01
--- /dev/null
+++ b/src/qreg.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2012-2021 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include <glib.h>
+
+#include "sciteco.h"
+#include "view.h"
+#include "doc.h"
+#include "undo.h"
+#include "string-utils.h"
+#include "rb3str.h"
+
+/*
+ * Forward declarations.
+ */
+typedef struct teco_qreg_t teco_qreg_t;
+/* Could be avoided by moving teco_qreg_execute() to the end of the file instead... */
+typedef struct teco_qreg_table_t teco_qreg_table_t;
+
+extern teco_view_t *teco_qreg_view;
+
+/*
+ * NOTE: This is not "hidden" in qreg.c, so that we won't need wrapper
+ * functions for every vtable method.
+ *
+ * FIXME: Use TECO_DECLARE_VTABLE_METHOD(gboolean, teco_qreg, set_integer, teco_qreg_t *, teco_int_t, GError **);
+ * ...
+ * teco_qreg_set_integer_t set_integer;
+ */
+typedef const struct {
+ gboolean (*set_integer)(teco_qreg_t *qreg, teco_int_t value, GError **error);
+ gboolean (*undo_set_integer)(teco_qreg_t *qreg, GError **error);
+ gboolean (*get_integer)(teco_qreg_t *qreg, teco_int_t *ret, GError **error);
+
+ gboolean (*set_string)(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error);
+ gboolean (*undo_set_string)(teco_qreg_t *qreg, GError **error);
+ gboolean (*append_string)(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error);
+ gboolean (*undo_append_string)(teco_qreg_t *qreg, GError **error);
+
+ gboolean (*get_string)(teco_qreg_t *qreg, gchar **str, gsize *len, GError **error);
+ gint (*get_character)(teco_qreg_t *qreg, guint position, GError **error);
+
+ /*
+ * These callbacks exist only to optimize teco_qreg_stack_push|pop()
+ * for plain Q-Registers making [q and ]q quite efficient operations even on rubout.
+ * On the other hand, this unnecessarily complicates teco_qreg_t derivations.
+ */
+ gboolean (*exchange_string)(teco_qreg_t *qreg, teco_doc_t *src, GError **error);
+ gboolean (*undo_exchange_string)(teco_qreg_t *qreg, teco_doc_t *src, GError **error);
+
+ gboolean (*edit)(teco_qreg_t *qreg, GError **error);
+ gboolean (*undo_edit)(teco_qreg_t *qreg, GError **error);
+} teco_qreg_vtable_t;
+
+/** @extends teco_rb3str_head_t */
+struct teco_qreg_t {
+ /*
+ * NOTE: Must be the first member since we "upcast" to teco_qreg_t
+ */
+ teco_rb3str_head_t head;
+
+ teco_qreg_vtable_t *vtable;
+
+ teco_int_t integer;
+ teco_doc_t string;
+
+ /*
+ * Whether to generate undo tokens (unnecessary for registers
+ * in local qreg tables in macro invocations).
+ *
+ * FIXME: Every QRegister has this field, but it only differs
+ * between local and global QRegisters. This wastes space.
+ * Or by deferring any decision about undo token creation to a layer
+ * that knows which table it is accessing.
+ * On the other hand, we will need another flag like
+ * teco_qreg_current_must_undo.
+ *
+ * Otherwise, it might be possible to use a least significant bit
+ * in one of the pointers...
+ */
+ gboolean must_undo;
+};
+
+teco_qreg_t *teco_qreg_plain_new(const gchar *name, gsize len);
+teco_qreg_t *teco_qreg_bufferinfo_new(void);
+teco_qreg_t *teco_qreg_workingdir_new(void);
+teco_qreg_t *teco_qreg_clipboard_new(const gchar *name);
+
+gboolean teco_qreg_execute(teco_qreg_t *qreg, teco_qreg_table_t *qreg_table_locals, GError **error);
+
+void teco_qreg_undo_set_eol_mode(teco_qreg_t *qreg);
+void teco_qreg_set_eol_mode(teco_qreg_t *qreg, gint mode);
+
+/*
+ * Load and save already care about undo token
+ * creation.
+ */
+gboolean teco_qreg_load(teco_qreg_t *qreg, const gchar *filename, GError **error);
+gboolean teco_qreg_save(teco_qreg_t *qreg, const gchar *filename, GError **error);
+
+/** @memberof teco_qreg_t */
+static inline void
+teco_qreg_free(teco_qreg_t *qreg)
+{
+ teco_doc_clear(&qreg->string);
+ teco_string_clear(&qreg->head.name);
+ g_free(qreg);
+}
+
+extern teco_qreg_t *teco_qreg_current;
+
+/** @extends teco_rb3str_tree_t */
+struct teco_qreg_table_t {
+ teco_rb3str_tree_t tree;
+
+ /*
+ * FIXME: Probably even this property can be eliminated.
+ * The only two tables with undo in the system are
+ * a) The global register table
+ * b) The top-level local register table.
+ */
+ gboolean must_undo;
+};
+
+void teco_qreg_table_init(teco_qreg_table_t *table, gboolean must_undo);
+
+/** @memberof teco_qreg_table_t */
+static inline teco_qreg_t *
+teco_qreg_table_insert(teco_qreg_table_t *table, teco_qreg_t *qreg)
+{
+ qreg->must_undo = table->must_undo; // FIXME
+ return (teco_qreg_t *)teco_rb3str_insert(&table->tree, TRUE, &qreg->head);
+}
+
+/** @memberof teco_qreg_table_t */
+static inline teco_qreg_t *
+teco_qreg_table_find(teco_qreg_table_t *table, const gchar *name, gsize len)
+{
+ return (teco_qreg_t *)teco_rb3str_find(&table->tree, TRUE, name, len);
+}
+
+teco_qreg_t *teco_qreg_table_edit_name(teco_qreg_table_t *table, const gchar *name,
+ gsize len, GError **error);
+
+/** @memberof teco_qreg_table_t */
+static inline gboolean
+teco_qreg_table_edit(teco_qreg_table_t *table, teco_qreg_t *qreg, GError **error)
+{
+ if (!qreg->vtable->edit(qreg, error))
+ return FALSE;
+ teco_qreg_current = qreg;
+ return TRUE;
+}
+
+gboolean teco_qreg_table_set_environ(teco_qreg_table_t *table, GError **error);
+gchar **teco_qreg_table_get_environ(teco_qreg_table_t *table, GError **error);
+
+gboolean teco_qreg_table_empty(teco_qreg_table_t *table, GError **error);
+void teco_qreg_table_clear(teco_qreg_table_t *table);
+
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(teco_qreg_table_t, teco_qreg_table_clear);
+
+extern teco_qreg_table_t teco_qreg_table_globals;
+
+gboolean teco_qreg_stack_push(teco_qreg_t *qreg, GError **error);
+gboolean teco_qreg_stack_pop(teco_qreg_t *qreg, GError **error);
+
+typedef enum {
+ TECO_ED_HOOK_ADD = 1,
+ TECO_ED_HOOK_EDIT,
+ TECO_ED_HOOK_CLOSE,
+ TECO_ED_HOOK_QUIT
+} teco_ed_hook_t;
+
+gboolean teco_ed_hook(teco_ed_hook_t type, GError **error);
+
+typedef enum {
+ TECO_MACHINE_QREGSPEC_ERROR = 0,
+ TECO_MACHINE_QREGSPEC_MORE,
+ TECO_MACHINE_QREGSPEC_DONE
+} teco_machine_qregspec_status_t;
+
+typedef enum {
+ /** Register must exist, else fail */
+ TECO_QREG_REQUIRED,
+ /**
+ * Return NULL if register does not exist.
+ * You can still call QRegSpecMachine::fail() to require it.
+ */
+ TECO_QREG_OPTIONAL,
+ /** Initialize register if it does not already exist */
+ TECO_QREG_OPTIONAL_INIT
+} teco_qreg_type_t;
+
+typedef struct teco_machine_qregspec_t teco_machine_qregspec_t;
+
+teco_machine_qregspec_t *teco_machine_qregspec_new(teco_qreg_type_t type,
+ teco_qreg_table_t *locals, gboolean must_undo);
+
+void teco_machine_qregspec_reset(teco_machine_qregspec_t *ctx);
+
+/*
+ * FIXME: This uses a forward declaration since we must not include parser.h
+ */
+struct teco_machine_stringbuilding_t *teco_machine_qregspec_get_stringbuilding(teco_machine_qregspec_t *ctx);
+
+teco_machine_qregspec_status_t teco_machine_qregspec_input(teco_machine_qregspec_t *ctx, gchar chr,
+ teco_qreg_t **result,
+ teco_qreg_table_t **result_table, GError **error);
+
+void teco_machine_qregspec_get_results(teco_machine_qregspec_t *ctx,
+ teco_qreg_t **result, teco_qreg_table_t **result_table);
+
+gboolean teco_machine_qregspec_auto_complete(teco_machine_qregspec_t *ctx, teco_string_t *insert);
+
+void teco_machine_qregspec_free(teco_machine_qregspec_t *ctx);
+
+/** @memberof teco_machine_qregspec_t */
+void undo__teco_machine_qregspec_free(teco_machine_qregspec_t *);
+TECO_DECLARE_UNDO_OBJECT(qregspec, teco_machine_qregspec_t *);
+
+#define teco_undo_qregspec_own(VAR) \
+ (*teco_undo_object_qregspec_push(&(VAR)))