aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2024-09-19 03:05:15 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2024-09-19 03:34:03 +0200
commit8fbd0b3ff42ae10c3735801ad17f5345fdc77766 (patch)
tree20db24f18d1b07d733478457a6455a5262b74ab3 /src
parent16c3089a1154f146dbab6a9d43f1c5df1c89739e (diff)
downloadsciteco-8fbd0b3ff42ae10c3735801ad17f5345fdc77766.tar.gz
"special" Q-Registers now support EQq/.../ (load) and E%q/.../ (save) commands
* @EQ$/.../ sets the current directory from the contents of the given file. @E%$/.../ stores the currend directory in the given file. * @EQ*/.../ will fail, just like ^U*...$. @E%*/.../ stores the current buffer's name in the given file. * It's especially useful with the clipboard registers. There could still be a minor bug in @E%~/.../ with regard to EOL normalization as teco_view_save() will use the EOL style of the current document, which may not be the style of the Q-Reg contents. Conversions can generally be avoided for these particular commands. But without teco_view_save() we'd have to care about save point creation.
Diffstat (limited to 'src')
-rw-r--r--src/qreg-commands.c4
-rw-r--r--src/qreg.c186
-rw-r--r--src/qreg.h14
-rw-r--r--src/ring.c2
4 files changed, 140 insertions, 66 deletions
diff --git a/src/qreg-commands.c b/src/qreg-commands.c
index a96eb5f..41e4465 100644
--- a/src/qreg-commands.c
+++ b/src/qreg-commands.c
@@ -149,7 +149,7 @@ teco_state_loadqreg_done(teco_machine_main_t *ctx, const teco_string_t *str, GEr
if (str->len > 0) {
/* Load file into Q-Register */
g_autofree gchar *filename = teco_file_expand_path(str->data);
- if (!teco_qreg_load(qreg, filename, error))
+ if (!qreg->vtable->load(qreg, filename, error))
return NULL;
} else {
/* Edit Q-Register */
@@ -202,7 +202,7 @@ teco_state_saveqreg_done(teco_machine_main_t *ctx, const teco_string_t *str, GEr
return &teco_state_start;
g_autofree gchar *filename = teco_file_expand_path(str->data);
- return teco_qreg_save(qreg, filename, error) ? &teco_state_start : NULL;
+ return qreg->vtable->save(qreg, filename, error) ? &teco_state_start : NULL;
}
/*$ E% E%q
diff --git a/src/qreg.c b/src/qreg.c
index 17b4830..c337dbe 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -133,56 +133,6 @@ teco_qreg_set_eol_mode(teco_qreg_t *qreg, gint mode)
teco_doc_edit(&teco_qreg_current->string, 0);
}
-/** @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_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;
-}
-
-/** @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, 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;
-}
-
static gboolean
teco_qreg_plain_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error)
{
@@ -343,6 +293,54 @@ 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.
@@ -362,6 +360,8 @@ teco_qreg_plain_undo_edit(teco_qreg_t *qreg, GError **error)
.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__ \
}
@@ -454,6 +454,55 @@ teco_qreg_external_get_length(teco_qreg_t *qreg, GError **error)
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().
@@ -464,6 +513,8 @@ teco_qreg_external_get_length(teco_qreg_t *qreg, GError **error)
.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__ \
)
@@ -549,7 +600,7 @@ teco_qreg_bufferinfo_get_string(teco_qreg_t *qreg, gchar **str, gsize *len,
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,
@@ -558,10 +609,14 @@ 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,
- /* we don't want to inherit all the other stuff from TECO_INIT_QREG_EXTERNAL(). */
- .edit = teco_qreg_external_edit,
- .get_character = teco_qreg_external_get_character,
- .get_length = teco_qreg_external_get_length
+ /*
+ * 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);
@@ -795,6 +850,24 @@ teco_qreg_clipboard_get_string(teco_qreg_t *qreg, gchar **str, gsize *len,
return TRUE;
}
+/*
+ * 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_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;
+
+ g_auto(teco_string_t) str = {NULL, 0};
+
+ 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)
@@ -804,7 +877,8 @@ teco_qreg_clipboard_new(const gchar *name)
.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_string = teco_qreg_clipboard_get_string,
+ .load = teco_qreg_clipboard_load
);
teco_qreg_t *qreg = teco_qreg_new(&vtable, "~", 1);
diff --git a/src/qreg.h b/src/qreg.h
index df4bdb4..85da898 100644
--- a/src/qreg.h
+++ b/src/qreg.h
@@ -72,6 +72,13 @@ typedef const struct {
gboolean (*edit)(teco_qreg_t *qreg, GError **error);
gboolean (*undo_edit)(teco_qreg_t *qreg, GError **error);
+
+ /*
+ * Load and save already care about undo token
+ * creation.
+ */
+ gboolean (*load)(teco_qreg_t *qreg, const gchar *filename, GError **error);
+ gboolean (*save)(teco_qreg_t *qreg, const gchar *filename, GError **error);
} teco_qreg_vtable_t;
/** @extends teco_rb3str_head_t */
@@ -113,13 +120,6 @@ gboolean teco_qreg_execute(teco_qreg_t *qreg, teco_qreg_table_t *qreg_table_loca
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)
diff --git a/src/ring.c b/src/ring.c
index 5a9e74e..6a4eae5 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -524,7 +524,7 @@ teco_state_save_file_done(teco_machine_main_t *ctx, const teco_string_t *str, GE
g_autofree gchar *filename = teco_file_expand_path(str->data);
if (teco_qreg_current) {
- if (!teco_qreg_save(teco_qreg_current, filename, error))
+ if (!teco_qreg_current->vtable->save(teco_qreg_current, filename, error))
return NULL;
} else {
if (!teco_buffer_save(teco_ring_current, *filename ? filename : NULL, error))