aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2025-07-13 18:35:32 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2025-07-13 18:35:32 +0300
commitfbab5e252f22de37d42cc6c2a014d690a9312565 (patch)
tree9552e56a343e5b9e273021ab53c376d773486447 /src
parent8c6de6cc718debf44f6056a4c34c4fbb13bc5020 (diff)
downloadsciteco-fbab5e252f22de37d42cc6c2a014d690a9312565.tar.gz
implemented <ER> command for reading a file into the current buffer
* This command exists in Video TECO. In Video TECO it also supports reading multiple files with a glob pattern -- we do not support that as I am not convinced of its usefulness. * teco_view_load() has been extended, so it can read into dot without discarding the existing document.
Diffstat (limited to 'src')
-rw-r--r--src/core-commands.c2
-rw-r--r--src/qreg.c2
-rw-r--r--src/ring.c36
-rw-r--r--src/ring.h1
-rw-r--r--src/view.c62
-rw-r--r--src/view.h13
6 files changed, 89 insertions, 27 deletions
diff --git a/src/core-commands.c b/src/core-commands.c
index 0ff2b81..8e31ae3 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -2686,6 +2686,8 @@ teco_state_ecommand_input(teco_machine_main_t *ctx, gunichar chr, GError **error
.modifier_at = TRUE, .modifier_colon = 1},
['W'] = {&teco_state_save_file,
.modifier_at = TRUE},
+ ['R'] = {&teco_state_read_file,
+ .modifier_at = TRUE},
/*
* Commands
diff --git a/src/qreg.c b/src/qreg.c
index 91f0deb..f08be17 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -337,7 +337,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)
diff --git a/src/ring.c b/src/ring.c
index 1c9a2cd..afda650 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -77,7 +77,7 @@ teco_buffer_undo_edit(teco_buffer_t *ctx)
static gboolean
teco_buffer_load(teco_buffer_t *ctx, const gchar *filename, GError **error)
{
- if (!teco_view_load(ctx->view, filename, error))
+ if (!teco_view_load(ctx->view, filename, TRUE, error))
return FALSE;
#if 0 /* NOTE: currently buffer cannot be dirty */
@@ -595,6 +595,40 @@ teco_state_save_file_done(teco_machine_main_t *ctx, const teco_string_t *str, GE
*/
TECO_DEFINE_STATE_EXPECTFILE(teco_state_save_file);
+static teco_state_t *
+teco_state_read_file_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
+ return &teco_state_start;
+
+ sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+
+ g_autofree gchar *filename = teco_file_expand_path(str->data);
+ /* FIXME: Add wrapper to interface.h? */
+ if (!teco_view_load(teco_interface_current_view, filename, FALSE, error))
+ return NULL;
+
+ if (teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0) != pos) {
+ teco_ring_dirtify();
+
+ if (teco_current_doc_must_undo())
+ undo__teco_interface_ssm(SCI_UNDO, 0, 0);
+ }
+
+ return &teco_state_start;
+}
+
+/*$ ER read
+ * ER<file>$ -- Read and insert file into current buffer
+ *
+ * Reads and inserts the given <file> into the current buffer or Q-Register at dot.
+ * Dot is left immediately after the given file.
+ */
+/*
+ * NOTE: Video TECO allows glob patterns as an argument.
+ */
+TECO_DEFINE_STATE_EXPECTFILE(teco_state_read_file);
+
/*$ EF close
* [n]EF -- Remove buffer from ring
* -EF
diff --git a/src/ring.h b/src/ring.h
index b75846a..6114839 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -99,6 +99,7 @@ void teco_ring_cleanup(void);
TECO_DECLARE_STATE(teco_state_edit_file);
TECO_DECLARE_STATE(teco_state_save_file);
+TECO_DECLARE_STATE(teco_state_read_file);
void teco_state_ecommand_close(teco_machine_main_t *ctx, GError **error);
diff --git a/src/view.c b/src/view.c
index e21d53a..d08728d 100644
--- a/src/view.c
+++ b/src/view.c
@@ -198,16 +198,22 @@ teco_view_set_representations(teco_view_t *ctx)
*
* @param ctx The view to load.
* @param channel Channel to read from.
+ * @param clear Whether to completely replace document
+ * (leaving dot at the beginning of the document) or insert at dot
+ * (leaving dot at the end of the insertion).
* @param error A GError.
* @return FALSE in case of a GError.
*
* @memberof teco_view_t
*/
gboolean
-teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, GError **error)
+teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel,
+ gboolean clear, GError **error)
{
gboolean ret = TRUE;
+ unsigned int message = SCI_ADDTEXT;
+
g_auto(teco_eol_reader_t) reader;
teco_eol_reader_init_gio(&reader, channel);
@@ -225,22 +231,27 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, GError **erro
SC_LINECHARACTERINDEX_UTF32, 0);
teco_view_ssm(ctx, SCI_BEGINUNDOACTION, 0, 0);
- teco_view_ssm(ctx, SCI_CLEARALL, 0, 0);
+ if (clear) {
+ teco_view_ssm(ctx, SCI_CLEARALL, 0, 0);
- /*
- * Preallocate memory based on the file size.
- * May waste a few bytes if file contains DOS EOLs
- * and EOL translation is enabled, but is faster.
- * NOTE: g_io_channel_unix_get_fd() should report the correct fd
- * on Windows, too.
- */
- struct stat stat_buf = {.st_size = 0};
- if (!fstat(g_io_channel_unix_get_fd(channel), &stat_buf) &&
- stat_buf.st_size > 0) {
- ret = teco_memory_check(stat_buf.st_size, error);
- if (!ret)
- goto cleanup;
- teco_view_ssm(ctx, SCI_ALLOCATE, stat_buf.st_size, 0);
+ /*
+ * Preallocate memory based on the file size.
+ * May waste a few bytes if file contains DOS EOLs
+ * and EOL translation is enabled, but is faster.
+ * NOTE: g_io_channel_unix_get_fd() should report the correct fd
+ * on Windows, too.
+ */
+ struct stat stat_buf = {.st_size = 0};
+ if (!fstat(g_io_channel_unix_get_fd(channel), &stat_buf) &&
+ stat_buf.st_size > 0) {
+ ret = teco_memory_check(stat_buf.st_size, error);
+ if (!ret)
+ goto cleanup;
+ teco_view_ssm(ctx, SCI_ALLOCATE, stat_buf.st_size, 0);
+ }
+
+ /* keep dot at beginning of document */
+ message = SCI_APPENDTEXT;
}
for (;;) {
@@ -258,7 +269,7 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, GError **erro
if (rc == G_IO_STATUS_EOF)
break;
- teco_view_ssm(ctx, SCI_APPENDTEXT, str.len, (sptr_t)str.data);
+ teco_view_ssm(ctx, message, str.len, (sptr_t)str.data);
/*
* Even if we checked initially, knowing the file size,
@@ -285,7 +296,7 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, GError **erro
* If it is enabled but the stream does not contain any
* EOL characters, the platform default is still assumed.
*/
- if (reader.eol_style >= 0)
+ if (clear && reader.eol_style >= 0)
teco_view_ssm(ctx, SCI_SETEOLMODE, reader.eol_style, 0);
if (reader.eol_style_inconsistent)
@@ -303,12 +314,21 @@ cleanup:
}
/**
- * Load view's document from file.
+ * Load file into view's document.
+ *
+ * @param ctx The view to load.
+ * @param filename File name to read
+ * @param clear Whether to completely replace document
+ * (leaving dot at the beginning of the document) or insert at dot
+ * (leaving dot at the end of the insertion).
+ * @param error A GError.
+ * @return FALSE in case of a GError.
*
* @memberof teco_view_t
*/
gboolean
-teco_view_load_from_file(teco_view_t *ctx, const gchar *filename, GError **error)
+teco_view_load_from_file(teco_view_t *ctx, const gchar *filename,
+ gboolean clear, GError **error)
{
g_autoptr(GIOChannel) channel = g_io_channel_new_file(filename, "r", error);
if (!channel)
@@ -322,7 +342,7 @@ teco_view_load_from_file(teco_view_t *ctx, const gchar *filename, GError **error
g_io_channel_set_encoding(channel, NULL, NULL);
g_io_channel_set_buffered(channel, FALSE);
- if (!teco_view_load_from_channel(ctx, channel, error)) {
+ if (!teco_view_load_from_channel(ctx, channel, clear, error)) {
g_prefix_error(error, "Error reading file \"%s\": ", filename);
return FALSE;
}
diff --git a/src/view.h b/src/view.h
index 7776e5b..4e4b85e 100644
--- a/src/view.h
+++ b/src/view.h
@@ -52,13 +52,17 @@ teco_view_set_scintilla_undo(teco_view_t *ctx, gboolean state)
teco_view_ssm(ctx, SCI_SETUNDOCOLLECTION, state, 0);
}
-gboolean teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, GError **error);
-gboolean teco_view_load_from_file(teco_view_t *ctx, const gchar *filename, GError **error);
+gboolean teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel,
+ gboolean clear, GError **error);
+gboolean teco_view_load_from_file(teco_view_t *ctx, const gchar *filename,
+ gboolean clear, GError **error);
/** @memberof teco_view_t */
-#define teco_view_load(CTX, FROM, ERROR) \
+#define teco_view_load(CTX, FROM, CLEAR, ERROR) \
(_Generic((FROM), GIOChannel * : teco_view_load_from_channel, \
- const gchar * : teco_view_load_from_file)((CTX), (FROM), (ERROR)))
+ gchar * : teco_view_load_from_file, \
+ const gchar * : teco_view_load_from_file)((CTX), (FROM), \
+ (CLEAR), (ERROR)))
gboolean teco_view_save_to_channel(teco_view_t *ctx, GIOChannel *channel, GError **error);
gboolean teco_view_save_to_file(teco_view_t *ctx, const gchar *filename, GError **error);
@@ -66,6 +70,7 @@ gboolean teco_view_save_to_file(teco_view_t *ctx, const gchar *filename, GError
/** @memberof teco_view_t */
#define teco_view_save(CTX, TO, ERROR) \
(_Generic((TO), GIOChannel * : teco_view_save_to_channel, \
+ gchar * : teco_view_save_to_file, \
const gchar * : teco_view_save_to_file)((CTX), (TO), (ERROR)))
/** @pure @memberof teco_view_t */