[evolution/449-support-markdown-in-composer: 14/15] EMarkdownEditor: Implement more EContentEditor methods




commit da1f2a6097cabf7bc43e9625783b6a9f25e70a43
Author: Milan Crha <mcrha redhat com>
Date:   Mon Feb 7 16:06:58 2022 +0100

    EMarkdownEditor: Implement more EContentEditor methods
    
    Also do related changes in the EHTMLEdtior and the EMsgComposer.

 src/composer/e-msg-composer.c  |   4 +-
 src/e-util/e-content-editor.c  |  52 ++++++++
 src/e-util/e-content-editor.h  |   6 +-
 src/e-util/e-html-editor.c     |  69 +++++++++-
 src/e-util/e-markdown-editor.c | 290 +++++++++++++++++++++++++++++++++++++++--
 src/e-util/e-markdown-editor.h |   4 +
 6 files changed, 410 insertions(+), 15 deletions(-)
---
diff --git a/src/composer/e-msg-composer.c b/src/composer/e-msg-composer.c
index cea20f8cc1..97cbdfd933 100644
--- a/src/composer/e-msg-composer.c
+++ b/src/composer/e-msg-composer.c
@@ -2764,11 +2764,11 @@ msg_composer_key_press_event (GtkWidget *widget,
        }
 
        if (event->keyval == GDK_KEY_Tab && gtk_widget_is_focus (input_widget)) {
-               gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
+               e_content_editor_grab_focus (cnt_editor);
                return TRUE;
        }
 
-       if (gtk_widget_is_focus (GTK_WIDGET (cnt_editor))) {
+       if (e_content_editor_is_focus (cnt_editor)) {
                if (event->keyval == GDK_KEY_ISO_Left_Tab) {
                        gboolean view_processed = FALSE;
 
diff --git a/src/e-util/e-content-editor.c b/src/e-util/e-content-editor.c
index 73c9b7018c..61971e6867 100644
--- a/src/e-util/e-content-editor.c
+++ b/src/e-util/e-content-editor.c
@@ -666,6 +666,58 @@ e_content_editor_supports_mode (EContentEditor *editor,
                iface->supports_mode (editor, mode);
 }
 
+/**
+ * e_content_editor_grab_focus:
+ * @editor: an #EContentEditor
+ *
+ * A method to grab focus on the @editor. This is an optional method,
+ * the default implementation calls gtk_widget_grab_focus().
+ *
+ * Since: 3.44
+ **/
+void
+e_content_editor_grab_focus (EContentEditor *editor)
+{
+       EContentEditorInterface *iface;
+
+       g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+       iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+       g_return_if_fail (iface != NULL);
+
+       if (iface->grab_focus)
+               iface->grab_focus (editor);
+       else
+               gtk_widget_grab_focus (GTK_WIDGET (editor));
+}
+
+/**
+ * e_content_editor_is_focus:
+ * @editor: an #EContentEditor
+ *
+ * Returns, whether the @editor is focused. This is an optional method,
+ * the default implementation calls gtk_widget_is_focus().
+ *
+ * Returns: whether the @editor is focused
+ *
+ * Since: 3.44
+ **/
+gboolean
+e_content_editor_is_focus (EContentEditor *editor)
+{
+       EContentEditorInterface *iface;
+
+       g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+       iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+       g_return_val_if_fail (iface != NULL, FALSE);
+
+       if (iface->is_focus)
+               return iface->is_focus (editor);
+       else
+               return gtk_widget_is_focus (GTK_WIDGET (editor));
+}
+
 ESpellChecker *
 e_content_editor_ref_spell_checker (EContentEditor *editor)
 {
diff --git a/src/e-util/e-content-editor.h b/src/e-util/e-content-editor.h
index 193dd4a164..487e45ab66 100644
--- a/src/e-util/e-content-editor.h
+++ b/src/e-util/e-content-editor.h
@@ -428,9 +428,11 @@ struct _EContentEditorInterface {
 
        gboolean        (*supports_mode)                (EContentEditor *editor,
                                                         EContentEditorMode mode);
+       void            (*grab_focus)                   (EContentEditor *editor);
+       gboolean        (*is_focus)                     (EContentEditor *editor);
 
        /* padding for future expansion */
-       gpointer reserved[19];
+       gpointer reserved[17];
 };
 
 /* Properties */
@@ -439,6 +441,8 @@ ESpellChecker *     e_content_editor_ref_spell_checker
                                                (EContentEditor *editor);
 gboolean       e_content_editor_supports_mode  (EContentEditor *editor,
                                                 EContentEditorMode mode);
+void           e_content_editor_grab_focus     (EContentEditor *editor);
+gboolean       e_content_editor_is_focus       (EContentEditor *editor);
 gboolean       e_content_editor_is_malfunction (EContentEditor *editor);
 gboolean       e_content_editor_can_cut        (EContentEditor *editor);
 gboolean       e_content_editor_can_copy       (EContentEditor *editor);
diff --git a/src/e-util/e-html-editor.c b/src/e-util/e-html-editor.c
index 8a74a8bdcf..8c5c4003ab 100644
--- a/src/e-util/e-html-editor.c
+++ b/src/e-util/e-html-editor.c
@@ -1527,6 +1527,56 @@ e_html_editor_register_content_editor (EHTMLEditor *editor,
        }
 }
 
+static void
+e_html_editor_update_content_on_mode_change_cb (GObject *source_object,
+                                               GAsyncResult *result,
+                                               gpointer user_data)
+{
+       GWeakRef *weak_ref = user_data;
+       EContentEditorContentHash *content_hash;
+       EContentEditor *cnt_editor;
+       EHTMLEditor *editor;
+
+       g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+       g_return_if_fail (weak_ref != NULL);
+
+       editor = g_weak_ref_get (weak_ref);
+
+       e_weak_ref_free (weak_ref);
+
+       if (!editor)
+               return;
+
+       cnt_editor = E_CONTENT_EDITOR (source_object);
+       content_hash = e_content_editor_get_content_finish (cnt_editor, result, NULL);
+
+       if (content_hash) {
+               gpointer text;
+
+               text = e_content_editor_util_get_content_data (content_hash, 
E_CONTENT_EDITOR_GET_TO_SEND_HTML);
+
+               if (editor->priv->mode == E_CONTENT_EDITOR_MODE_HTML && text) {
+                       e_content_editor_insert_content (editor->priv->use_content_editor, text,
+                               E_CONTENT_EDITOR_INSERT_CONVERT |
+                               E_CONTENT_EDITOR_INSERT_TEXT_HTML |
+                               E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
+               } else {
+                       text = e_content_editor_util_get_content_data (content_hash, 
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
+
+                       if (text) {
+                               e_content_editor_insert_content (editor->priv->use_content_editor, text,
+                                       E_CONTENT_EDITOR_INSERT_CONVERT |
+                                       E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
+                                       E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
+                       }
+               }
+
+               e_content_editor_util_free_content_hash (content_hash);
+       }
+
+       g_object_unref (editor);
+}
+
 /**
  * e_html_editor_get_mode:
  * @editor: an #EHTMLEditor
@@ -1570,11 +1620,24 @@ e_html_editor_set_mode (EHTMLEditor *editor,
 
        if (cnt_editor) {
                if (cnt_editor != editor->priv->use_content_editor) {
-                       if (editor->priv->use_content_editor)
+                       gboolean is_focused = FALSE;
+
+                       if (editor->priv->use_content_editor) {
+                               is_focused = e_content_editor_is_focus (editor->priv->use_content_editor);
+
+                               e_content_editor_get_content (editor->priv->use_content_editor,
+                                       E_CONTENT_EDITOR_GET_TO_SEND_HTML | 
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN,
+                                       "localhost", NULL,
+                                       e_html_editor_update_content_on_mode_change_cb,
+                                       e_weak_ref_new (editor));
+
                                gtk_widget_hide (GTK_WIDGET (editor->priv->use_content_editor));
+                       }
+
+                       gtk_widget_show (GTK_WIDGET (cnt_editor));
 
-                       if (cnt_editor)
-                               gtk_widget_show (GTK_WIDGET (cnt_editor));
+                       if (is_focused)
+                               e_content_editor_grab_focus (cnt_editor);
                }
 
                editor->priv->mode = mode;
diff --git a/src/e-util/e-markdown-editor.c b/src/e-util/e-markdown-editor.c
index e0909add2a..84a51c5252 100644
--- a/src/e-util/e-markdown-editor.c
+++ b/src/e-util/e-markdown-editor.c
@@ -36,8 +36,7 @@ struct _EMarkdownEditorPrivate {
        gboolean can_undo;
        gboolean changed;
        EContentEditorMode mode;
-       gboolean spell_check_enabled;
-       ESpellChecker *spell_check;
+       ESpellChecker *spell_checker; /* this is not used internally */
        EThreeState start_bottom;
        EThreeState top_signature;
 };
@@ -89,6 +88,65 @@ enum {
 
 static guint signals[LAST_SIGNAL];
 
+typedef void (* AsyncCallback) (EMarkdownEditor *self,
+                               gpointer user_data);
+
+typedef struct _AsyncData {
+       EMarkdownEditor *self;
+       AsyncCallback callback;
+       gpointer user_data;
+} AsyncData;
+
+static AsyncData *
+async_data_new (EMarkdownEditor *self,
+               AsyncCallback callback,
+               gpointer user_data)
+{
+       AsyncData *data;
+
+       data = g_slice_new (AsyncData);
+       data->self = g_object_ref (self);
+       data->callback = callback;
+       data->user_data = user_data;
+
+       return data;
+}
+
+static void
+async_data_free (gpointer ptr)
+{
+       AsyncData *data = ptr;
+
+       if (data) {
+               g_clear_object (&data->self);
+               g_slice_free (AsyncData, data);
+       }
+}
+
+static gboolean
+e_markdown_editor_call_async_cb (gpointer user_data)
+{
+       AsyncData *data = user_data;
+
+       g_return_val_if_fail (data != NULL, FALSE);
+       g_return_val_if_fail (data->callback != NULL, FALSE);
+
+       data->callback (data->self, data->user_data);
+
+       return FALSE;
+}
+
+static void
+e_markdown_editor_call_async (EMarkdownEditor *self,
+                             AsyncCallback callback,
+                             gpointer user_data)
+{
+       g_timeout_add_full (G_PRIORITY_HIGH, 1,
+               e_markdown_editor_call_async_cb,
+               async_data_new (self, callback, user_data),
+               async_data_free);
+}
+
 static gboolean
 e_markdown_editor_supports_mode (EContentEditor *cnt_editor,
                                 EContentEditorMode mode)
@@ -100,11 +158,53 @@ e_markdown_editor_supports_mode (EContentEditor *cnt_editor,
                mode == E_CONTENT_EDITOR_MODE_MARKDOWN_PLAIN_TEXT;
 }
 
+static void
+e_markdown_editor_grab_focus (EContentEditor *cnt_editor)
+{
+       EMarkdownEditor *self = E_MARKDOWN_EDITOR (cnt_editor);
+
+       gtk_widget_grab_focus (GTK_WIDGET (self->priv->text_view));
+}
+
+static gboolean
+e_markdown_editor_is_focus (EContentEditor *cnt_editor)
+{
+       EMarkdownEditor *self = E_MARKDOWN_EDITOR (cnt_editor);
+
+       return gtk_widget_is_focus (GTK_WIDGET (self->priv->text_view));
+}
+
+typedef struct _InitAsyncData {
+       EContentEditorInitializedCallback callback;
+       gpointer user_data;
+} InitAsyncData;
+
+static void
+e_markdown_editor_initialize_done (EMarkdownEditor *self,
+                                  gpointer user_data)
+{
+       InitAsyncData *data = user_data;
+
+       g_return_if_fail (data != NULL);
+       g_return_if_fail (data->callback != NULL);
+
+       data->callback (E_CONTENT_EDITOR (self), data->user_data);
+
+       g_slice_free (InitAsyncData, data);
+}
+
 static void
 e_markdown_editor_initialize (EContentEditor *cnt_editor,
                              EContentEditorInitializedCallback callback,
                              gpointer user_data)
 {
+       InitAsyncData *data;
+
+       data = g_slice_new (InitAsyncData);
+       data->callback = callback;
+       data->user_data = user_data;
+
+       e_markdown_editor_call_async (E_MARKDOWN_EDITOR (cnt_editor), e_markdown_editor_initialize_done, 
data);
 }
 
 static gboolean
@@ -123,6 +223,47 @@ e_markdown_editor_insert_content (EContentEditor *cnt_editor,
                                  const gchar *content,
                                  EContentEditorInsertContentFlags flags)
 {
+       EMarkdownEditor *self;
+       gchar *text = NULL;
+
+       g_return_if_fail (E_IS_MARKDOWN_EDITOR (cnt_editor));
+       g_return_if_fail (content != NULL);
+
+       self = E_MARKDOWN_EDITOR (cnt_editor);
+
+       if ((flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML) != 0) {
+               text = e_markdown_util_html_to_text (content, -1);
+               content = text;
+       }
+
+       if ((flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) != 0) {
+               e_markdown_editor_set_text (self, content);
+       } else if ((flags & E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT) != 0) {
+               GtkTextBuffer *text_buffer;
+               GString *quoted;
+               gint ii;
+
+               quoted = g_string_sized_new (strlen (content) + 4);
+               g_string_append (quoted, "> ");
+               g_string_append (quoted, content);
+
+               for (ii = 0; ii < quoted->len; ii++) {
+                       if (quoted->str[ii] == '\n' && ii + 1 < quoted->len)
+                               g_string_insert (quoted, ii + 1, "> ");
+               }
+
+               text_buffer = gtk_text_view_get_buffer (self->priv->text_view);
+               gtk_text_buffer_insert_at_cursor (text_buffer, quoted->str, -1);
+
+               g_string_free (quoted, TRUE);
+       } else {
+               GtkTextBuffer *text_buffer;
+
+               text_buffer = gtk_text_view_get_buffer (self->priv->text_view);
+               gtk_text_buffer_insert_at_cursor (text_buffer, content, -1);
+       }
+
+       g_free (text);
 }
 
 static void
@@ -133,6 +274,78 @@ e_markdown_editor_get_content (EContentEditor *cnt_editor,
                               GAsyncReadyCallback callback,
                               gpointer user_data)
 {
+       GTask *task;
+       EContentEditorContentHash *content_hash;
+
+       content_hash = e_content_editor_util_new_content_hash ();
+       if ((flags & E_CONTENT_EDITOR_GET_RAW_BODY_HTML) != 0 ||
+           (flags & E_CONTENT_EDITOR_GET_TO_SEND_HTML) != 0) {
+               gchar *html;
+
+               html = e_markdown_editor_dup_html (E_MARKDOWN_EDITOR (cnt_editor));
+
+               if (html) {
+                       if ((flags & E_CONTENT_EDITOR_GET_RAW_BODY_HTML) != 0 &&
+                           (flags & E_CONTENT_EDITOR_GET_TO_SEND_HTML) != 0) {
+                               e_content_editor_util_put_content_data (content_hash,
+                                       E_CONTENT_EDITOR_GET_RAW_BODY_HTML, html);
+                               e_content_editor_util_take_content_data (content_hash,
+                                       E_CONTENT_EDITOR_GET_TO_SEND_HTML, html, g_free);
+                       } else if ((flags & E_CONTENT_EDITOR_GET_RAW_BODY_HTML) != 0) {
+                               e_content_editor_util_take_content_data (content_hash,
+                                       E_CONTENT_EDITOR_GET_RAW_BODY_HTML, html, g_free);
+                       } else {
+                               e_content_editor_util_take_content_data (content_hash,
+                                       E_CONTENT_EDITOR_GET_TO_SEND_HTML, html, g_free);
+                       }
+               }
+       }
+
+       if ((flags & E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN) != 0 ||
+           (flags & E_CONTENT_EDITOR_GET_RAW_DRAFT) != 0 ||
+           (flags & E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) != 0) {
+               gchar *text;
+
+               text = e_markdown_editor_dup_text (E_MARKDOWN_EDITOR (cnt_editor));
+
+               if (text) {
+                       gint n_formats = ((flags & E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN) != 0 ? 1 : 0) +
+                                        ((flags & E_CONTENT_EDITOR_GET_RAW_DRAFT) != 0 ? 1 : 0) +
+                                        ((flags & E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) != 0 ? 1 : 0);
+
+                       if (n_formats == 1) {
+                               EContentEditorGetContentFlags format;
+                               if ((flags & E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN) != 0)
+                                       format = E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN;
+                               else if ((flags & E_CONTENT_EDITOR_GET_RAW_DRAFT) != 0)
+                                       format = E_CONTENT_EDITOR_GET_RAW_DRAFT;
+                               else
+                                       format = E_CONTENT_EDITOR_GET_TO_SEND_PLAIN;
+
+                               e_content_editor_util_take_content_data (content_hash,
+                                       format, text, g_free);
+                       } else {
+                               if ((flags & E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN) != 0)
+                                       e_content_editor_util_put_content_data (content_hash,
+                                               E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN, text);
+
+                               if ((flags & E_CONTENT_EDITOR_GET_RAW_DRAFT) != 0)
+                                       e_content_editor_util_put_content_data (content_hash,
+                                               E_CONTENT_EDITOR_GET_RAW_DRAFT, text);
+
+                               if ((flags & E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) != 0)
+                                       e_content_editor_util_put_content_data (content_hash,
+                                               E_CONTENT_EDITOR_GET_TO_SEND_PLAIN, text);
+
+                               g_free (text);
+                       }
+               }
+       }
+
+       task = g_task_new (cnt_editor, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_markdown_editor_get_content);
+       g_task_return_pointer (task, content_hash, (GDestroyNotify) e_content_editor_util_free_content_hash);
+       g_object_unref (task);
 }
 
 static EContentEditorContentHash *
@@ -140,7 +353,9 @@ e_markdown_editor_get_content_finish (EContentEditor *cnt_editor,
                                      GAsyncResult *result,
                                      GError **error)
 {
-       return NULL;
+       g_return_val_if_fail (g_task_is_valid (result, cnt_editor), NULL);
+
+       return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static gboolean
@@ -228,15 +443,16 @@ e_markdown_editor_set_mode (EMarkdownEditor *self,
 static gboolean
 e_markdown_editor_get_spell_check_enabled (EMarkdownEditor *self)
 {
-       return self->priv->spell_check_enabled;
+       return e_spell_text_view_get_enabled (self->priv->text_view);
 }
 
 static void
 e_markdown_editor_set_spell_check_enabled (EMarkdownEditor *self,
                                           gboolean value)
 {
-       if ((self->priv->spell_check_enabled ? 1 : 0) != (value ? 1 : 0)) {
-               self->priv->spell_check_enabled = value;
+       gboolean spell_check_enabled = e_markdown_editor_get_spell_check_enabled (self);
+       if ((spell_check_enabled ? 1 : 0) != (value ? 1 : 0)) {
+               e_spell_text_view_set_enabled (self->priv->text_view, value);
                g_object_notify (G_OBJECT (self), "spell-check-enabled");
        }
 }
@@ -244,7 +460,7 @@ e_markdown_editor_set_spell_check_enabled (EMarkdownEditor *self,
 static ESpellChecker *
 e_markdown_editor_get_spell_checker (EMarkdownEditor *self)
 {
-       return self->priv->spell_check;
+       return self->priv->spell_checker;
 }
 
 static EThreeState
@@ -1056,15 +1272,27 @@ e_markdown_editor_constructed (GObject *object)
        e_signal_connect_notify_object (self->priv->text_view, "notify::editable", G_CALLBACK 
(e_markdown_editor_notify_editable_cb), self, 0);
 }
 
+static void
+e_markdown_editor_dispose (GObject *object)
+{
+       EMarkdownEditor *self = E_MARKDOWN_EDITOR (object);
+
+       g_clear_object (&self->priv->spell_checker);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_markdown_editor_parent_class)->dispose (object);
+}
+
 static void
 e_markdown_editor_class_init (EMarkdownEditorClass *klass)
 {
        GObjectClass *object_class;
 
        object_class = G_OBJECT_CLASS (klass);
-       object_class->constructed = e_markdown_editor_constructed;
        object_class->get_property = e_markdown_editor_get_property;
        object_class->set_property = e_markdown_editor_set_property;
+       object_class->constructed = e_markdown_editor_constructed;
+       object_class->dispose = e_markdown_editor_dispose;
 
        g_object_class_override_property (object_class, PROP_IS_MALFUNCTION, "is-malfunction");
        g_object_class_override_property (object_class, PROP_CAN_COPY, "can-copy");
@@ -1117,6 +1345,8 @@ static void
 e_markdown_editor_content_editor_init (EContentEditorInterface *iface)
 {
        iface->supports_mode = e_markdown_editor_supports_mode;
+       iface->grab_focus = e_markdown_editor_grab_focus;
+       iface->is_focus = e_markdown_editor_is_focus;
        iface->initialize = e_markdown_editor_initialize;
        iface->is_ready = e_markdown_editor_is_ready;
        iface->update_styles = e_markdown_editor_update_styles;
@@ -1138,7 +1368,7 @@ e_markdown_editor_content_editor_init (EContentEditorInterface *iface)
        iface->find = e_markdown_editor_find;
        iface->replace = e_markdown_editor_replace;
        iface->replace_all = e_markdown_editor_replace_all;
-       iface->get_current_signature_uid =  e_markdown_editor_get_current_signature_uid;
+       iface->get_current_signature_uid = e_markdown_editor_get_current_signature_uid;
        iface->insert_signature = e_markdown_editor_insert_signature;*/
 }
 
@@ -1147,6 +1377,7 @@ e_markdown_editor_init (EMarkdownEditor *self)
 {
        self->priv = e_markdown_editor_get_instance_private (self);
 
+       self->priv->spell_checker = e_spell_checker_new ();
        self->priv->mode = E_CONTENT_EDITOR_MODE_MARKDOWN_PLAIN_TEXT;
        self->priv->start_bottom = E_THREE_STATE_INCONSISTENT;
        self->priv->top_signature = E_THREE_STATE_INCONSISTENT;
@@ -1200,6 +1431,28 @@ e_markdown_editor_get_action_toolbar (EMarkdownEditor *self)
        return self->priv->action_toolbar;
 }
 
+/**
+ * e_markdown_editor_set_text:
+ * @self an #EMarkdownEditor
+ * @text: text to set
+ *
+ * Sets the @text as the editor content.
+ *
+ * Since: 3.44
+ **/
+void
+e_markdown_editor_set_text (EMarkdownEditor *self,
+                           const gchar *text)
+{
+       GtkTextBuffer *buffer;
+
+       g_return_if_fail (E_IS_MARKDOWN_EDITOR (self));
+       g_return_if_fail (text != NULL);
+
+       buffer = gtk_text_view_get_buffer (self->priv->text_view);
+       gtk_text_buffer_set_text (buffer, text, -1);
+}
+
 /**
  * e_markdown_editor_dup_text:
  * @self: an #EMarkdownEditor
@@ -1302,3 +1555,22 @@ e_markdown_util_text_to_html (const gchar *plain_text,
        return NULL;
        #endif
 }
+
+/**
+ * e_markdown_util_html_to_text:
+ * @html: a text in HTML
+ * @length: length of the @html, or -1 when it's nul-terminated
+ *
+ * Convert @html into the markdown text.
+ *
+ * Returns: (transfer full) (nullable): HTML converted into markdown.
+ *    Free the string with g_free(), when no longer needed.
+ *
+ * Since: 3.44
+ **/
+gchar *
+e_markdown_util_html_to_text (const gchar *html,
+                             gssize length)
+{
+       return NULL;
+}
diff --git a/src/e-util/e-markdown-editor.h b/src/e-util/e-markdown-editor.h
index 0cacea1493..a24e5f67eb 100644
--- a/src/e-util/e-markdown-editor.h
+++ b/src/e-util/e-markdown-editor.h
@@ -51,11 +51,15 @@ GType               e_markdown_editor_get_type              (void) G_GNUC_CONST;
 GtkWidget *    e_markdown_editor_new                   (void);
 GtkTextView *  e_markdown_editor_get_text_view         (EMarkdownEditor *self);
 GtkToolbar *   e_markdown_editor_get_action_toolbar    (EMarkdownEditor *self);
+void           e_markdown_editor_set_text              (EMarkdownEditor *self,
+                                                        const gchar *text);
 gchar *                e_markdown_editor_dup_text              (EMarkdownEditor *self);
 gchar *                e_markdown_editor_dup_html              (EMarkdownEditor *self);
 
 gchar *                e_markdown_util_text_to_html            (const gchar *plain_text,
                                                         gssize length);
+gchar *                e_markdown_util_html_to_text            (const gchar *html,
+                                                        gssize length);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]