aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/doc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc.c')
-rw-r--r--src/doc.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/doc.c b/src/doc.c
new file mode 100644
index 0000000..41acf40
--- /dev/null
+++ b/src/doc.c
@@ -0,0 +1,209 @@
+/*
+ * 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+#include <Scintilla.h>
+
+#include "sciteco.h"
+#include "view.h"
+#include "undo.h"
+#include "qreg.h"
+#include "doc.h"
+
+static inline teco_doc_scintilla_t *
+teco_doc_get_scintilla(teco_doc_t *ctx)
+{
+ if (G_UNLIKELY(!ctx->doc))
+ ctx->doc = (teco_doc_scintilla_t *)teco_view_ssm(teco_qreg_view, SCI_CREATEDOCUMENT, 0, 0);
+ return ctx->doc;
+}
+
+/** @memberof teco_doc_t */
+void
+teco_doc_edit(teco_doc_t *ctx)
+{
+ /*
+ * FIXME: SCI_SETREPRESENTATION does not redraw
+ * the screen - also that would be very slow.
+ * Since SCI_SETDOCPOINTER resets the representation
+ * (this should probably be fixed in Scintilla),
+ * the screen is garbled since the layout cache
+ * is calculated with the default representations.
+ * We work around this by temporarily disabling the
+ * layout cache.
+ */
+ gint old_mode = teco_view_ssm(teco_qreg_view, SCI_GETLAYOUTCACHE, 0, 0);
+ teco_view_ssm(teco_qreg_view, SCI_SETLAYOUTCACHE, SC_CACHE_NONE, 0);
+
+ teco_view_ssm(teco_qreg_view, SCI_SETDOCPOINTER, 0,
+ (sptr_t)teco_doc_get_scintilla(ctx));
+ teco_view_ssm(teco_qreg_view, SCI_SETFIRSTVISIBLELINE, ctx->first_line, 0);
+ teco_view_ssm(teco_qreg_view, SCI_SETXOFFSET, ctx->xoffset, 0);
+ teco_view_ssm(teco_qreg_view, SCI_SETSEL, ctx->anchor, (sptr_t)ctx->dot);
+
+ /*
+ * Default TECO-style character representations.
+ * They are reset on EVERY SETDOCPOINTER call by Scintilla.
+ */
+ teco_view_set_representations(teco_qreg_view);
+
+ teco_view_ssm(teco_qreg_view, SCI_SETLAYOUTCACHE, old_mode, 0);
+}
+
+/** @memberof teco_doc_t */
+void
+teco_doc_undo_edit(teco_doc_t *ctx)
+{
+ /*
+ * FIXME: see above in teco_doc_edit()
+ */
+ undo__teco_view_ssm(teco_qreg_view, SCI_SETLAYOUTCACHE,
+ teco_view_ssm(teco_qreg_view, SCI_GETLAYOUTCACHE, 0, 0), 0);
+
+ undo__teco_view_set_representations(teco_qreg_view);
+
+ undo__teco_view_ssm(teco_qreg_view, SCI_SETSEL, ctx->anchor, (sptr_t)ctx->dot);
+ undo__teco_view_ssm(teco_qreg_view, SCI_SETXOFFSET, ctx->xoffset, 0);
+ undo__teco_view_ssm(teco_qreg_view, SCI_SETFIRSTVISIBLELINE, ctx->first_line, 0);
+ undo__teco_view_ssm(teco_qreg_view, SCI_SETDOCPOINTER, 0,
+ (sptr_t)teco_doc_get_scintilla(ctx));
+
+ undo__teco_view_ssm(teco_qreg_view, SCI_SETLAYOUTCACHE, SC_CACHE_NONE, 0);
+}
+
+/** @memberof teco_doc_t */
+void
+teco_doc_set_string(teco_doc_t *ctx, const gchar *str, gsize len)
+{
+ if (teco_qreg_current)
+ teco_doc_update(&teco_qreg_current->string, teco_qreg_view);
+
+ teco_doc_reset(ctx);
+ teco_doc_edit(ctx);
+
+ 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, 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);
+}
+
+/** @memberof teco_doc_t */
+void
+teco_doc_undo_set_string(teco_doc_t *ctx)
+{
+ /*
+ * Necessary, so that upon rubout the
+ * string's parameters are restored.
+ */
+ teco_doc_update(ctx, teco_qreg_view);
+
+ if (teco_qreg_current && teco_qreg_current->must_undo) // FIXME
+ teco_doc_undo_edit(&teco_qreg_current->string);
+
+ teco_doc_undo_reset(ctx);
+ undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0);
+
+ teco_doc_undo_edit(ctx);
+}
+
+/**
+ * Get a document as a string.
+ *
+ * @param ctx The document.
+ * @param str Pointer to a variable to hold the return string.
+ * It can be NULL if you are interested only in the string's length.
+ * Strings must be freed via g_free().
+ * @param len Where to store the string's length (mandatory).
+ *
+ * @see teco_qreg_vtable_t::get_string()
+ * @memberof teco_doc_t
+ */
+void
+teco_doc_get_string(teco_doc_t *ctx, gchar **str, gsize *len)
+{
+ if (!ctx->doc) {
+ if (str)
+ *str = NULL;
+ *len = 0;
+ return;
+ }
+
+ if (teco_qreg_current)
+ teco_doc_update(&teco_qreg_current->string, teco_qreg_view);
+
+ teco_doc_edit(ctx);
+
+ *len = teco_view_ssm(teco_qreg_view, SCI_GETLENGTH, 0, 0);
+ if (str) {
+ *str = g_malloc(*len + 1);
+ teco_view_ssm(teco_qreg_view, SCI_GETTEXT, *len + 1, (sptr_t)*str);
+ }
+
+ if (teco_qreg_current)
+ teco_doc_edit(&teco_qreg_current->string);
+}
+
+/** @memberof teco_doc_t */
+void
+teco_doc_update_from_view(teco_doc_t *ctx, teco_view_t *from)
+{
+ ctx->anchor = teco_view_ssm(from, SCI_GETANCHOR, 0, 0);
+ ctx->dot = teco_view_ssm(from, SCI_GETCURRENTPOS, 0, 0);
+ ctx->first_line = teco_view_ssm(from, SCI_GETFIRSTVISIBLELINE, 0, 0);
+ ctx->xoffset = teco_view_ssm(from, SCI_GETXOFFSET, 0, 0);
+}
+
+/** @memberof teco_doc_t */
+void
+teco_doc_update_from_doc(teco_doc_t *ctx, const teco_doc_t *from)
+{
+ ctx->anchor = from->anchor;
+ ctx->dot = from->dot;
+ ctx->first_line = from->first_line;
+ ctx->xoffset = from->xoffset;
+}
+
+/**
+ * Only for teco_qreg_stack_pop() which does some clever
+ * exchanging of document data (without any deep copying)
+ *
+ * @memberof teco_doc_t
+ */
+void
+teco_doc_exchange(teco_doc_t *ctx, teco_doc_t *other)
+{
+ teco_doc_t temp;
+ memcpy(&temp, ctx, sizeof(temp));
+ memcpy(ctx, other, sizeof(*ctx));
+ memcpy(other, &temp, sizeof(*other));
+}
+
+/** @memberof teco_doc_t */
+void
+teco_doc_clear(teco_doc_t *ctx)
+{
+ if (ctx->doc)
+ teco_view_ssm(teco_qreg_view, SCI_RELEASEDOCUMENT, 0, (sptr_t)ctx->doc);
+}