# HG changeset patch
# Node ID df5c478b12de
# Parent  777ace07ab22
diff --git a/demo/data/demo.ui b/demo/data/demo.ui
--- a/demo/data/demo.ui
+++ b/demo/data/demo.ui
@@ -299,17 +299,40 @@
       </item>
     </section>
   </menu>
-  <object class="TalkatuHtmlBuffer" id="buffer_html">
+  <object class="TalkatuBuffer" id="buffer_html">
+    <property name="action-group">
+      <object class="TalkatuActionGroup">
+        <property name="format">html</property>
+        <property name="buffer">buffer_html</property>
+      </object>
+    </property>
     <signal name="changed" handler="talkatu_demo_window_buffer_modified_cb"/>
   </object>
-  <object class="TalkatuMarkdownBuffer" id="buffer_markdown">
+  <object class="TalkatuBuffer" id="buffer_markdown">
+    <property name="action-group">
+      <object class="TalkatuActionGroup">
+        <property name="format">markdown</property>
+        <property name="buffer">buffer_markdown</property>
+      </object>
+    </property>
     <signal name="changed" handler="talkatu_demo_window_buffer_modified_cb"/>
   </object>
   <object class="TalkatuBuffer" id="buffer_plain">
+    <property name="action-group">
+      <object class="TalkatuActionGroup">
+        <property name="buffer">buffer_plain</property>
+      </object>
+    </property>
     <signal name="changed" handler="talkatu_demo_window_buffer_modified_cb"/>
   </object>
-  <object class="TalkatuWholeBuffer" id="buffer_whole">
+  <object class="TalkatuBuffer" id="buffer_whole">
     <property name="style">whole</property>
+    <property name="action-group">
+      <object class="TalkatuActionGroup">
+        <property name="format">html</property>
+        <property name="buffer">buffer_whole</property>
+      </object>
+    </property>
     <signal name="changed" handler="talkatu_demo_window_buffer_modified_cb"/>
   </object>
 </interface>
diff --git a/demo/talkatudemowindow.c b/demo/talkatudemowindow.c
--- a/demo/talkatudemowindow.c
+++ b/demo/talkatudemowindow.c
@@ -63,9 +63,11 @@
 			GtkTextIter iter;
 
 			mark = gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(window->buffer_html));
-			gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(window->buffer_html), &iter, mark);
+			gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(window->buffer_html),
+			                                 &iter, mark);
 
-			talkatu_html_buffer_insert_html(TALKATU_HTML_BUFFER(window->buffer_html), &iter, contents, len);
+			talkatu_markup_insert_html(TALKATU_BUFFER(window->buffer_html),
+			                           &iter, contents, len);
 			g_free(contents);
 		}
 
@@ -118,9 +120,11 @@
 			GtkTextIter iter;
 
 			mark = gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(window->buffer_markdown));
-			gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(window->buffer_markdown), &iter, mark);
+			gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(window->buffer_markdown),
+			                                 &iter, mark);
 
-			talkatu_markdown_buffer_insert_markdown(TALKATU_MARKDOWN_BUFFER(window->buffer_markdown), &iter, contents, len);
+			talkatu_markdown_insert(TALKATU_BUFFER(window->buffer_markdown),
+			                        &iter, contents, len);
 			g_free(contents);
 		}
 
diff --git a/meson.build b/meson.build
--- a/meson.build
+++ b/meson.build
@@ -1,7 +1,7 @@
 ###############################################################################
 # Project Info
 ###############################################################################
-project('talkatu', 'c', version : '0.1.1-dev',
+project('talkatu', 'c', version : '0.2.0-dev',
 	license : 'GPL-2.0-or-later',
 	meson_version : '>=0.58.0',
 	default_options : ['c_std=c17', 'warning_level=2'])
diff --git a/talkatu/meson.build b/talkatu/meson.build
--- a/talkatu/meson.build
+++ b/talkatu/meson.build
@@ -13,14 +13,14 @@
 	'talkatucodeset.h',
 	'talkatucore.h',
 	'talkatueditor.h',
+	'talkatuformat.h',
 	'talkatuhistory.h',
 	'talkatuhistoryrow.h',
-	'talkatuhtmlbuffer.h',
 	'talkatuhtmlpangorenderer.h',
 	'talkatuhtmlrenderer.h',
 	'talkatuinput.h',
 	'talkatulinkdialog.h',
-	'talkatumarkdownbuffer.h',
+	'talkatumarkdown.h',
 	'talkatumarkup.h',
 	'talkatumessage.h',
 	'talkatusimpleattachment.h',
@@ -29,7 +29,6 @@
 	'talkatutoolbar.h',
 	'talkatutypinglabel.h',
 	'talkatuview.h',
-	'talkatuwholebuffer.h',
 ]
 
 TALKATU_SOURCES = [
@@ -44,12 +43,11 @@
 	'talkatueditor.c',
 	'talkatuhistory.c',
 	'talkatuhistoryrow.c',
-	'talkatuhtmlbuffer.c',
 	'talkatuhtmlpangorenderer.c',
 	'talkatuhtmlrenderer.c',
 	'talkatuinput.c',
 	'talkatulinkdialog.c',
-	'talkatumarkdownbuffer.c',
+	'talkatumarkdown.c',
 	'talkatumarkup.c',
 	'talkatumessage.c',
 	'talkatusimpleattachment.c',
@@ -58,7 +56,6 @@
 	'talkatutoolbar.c',
 	'talkatutypinglabel.c',
 	'talkatuview.c',
-	'talkatuwholebuffer.c',
 ]
 
 TALKATU_PUBLIC_BUILT_HEADERS = [
@@ -89,6 +86,7 @@
 
 TALKATU_ENUM_HEADERS = [
 	'talkatubuffer.h',
+	'talkatuformat.h',
 	'talkatumessage.h',
 	'talkatutag.h',
 	'talkatuinput.h',
diff --git a/talkatu/talkatuactiongroup.h b/talkatu/talkatuactiongroup.h
--- a/talkatu/talkatuactiongroup.h
+++ b/talkatu/talkatuactiongroup.h
@@ -1,6 +1,6 @@
 /*
  * Talkatu - GTK widgets for chat applications
- * Copyright (C) 2017-2020 Gary Kramlich <grim@reaperworld.com>
+ * Copyright (C) 2017-2023 Gary Kramlich <grim@reaperworld.com>
  *
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,19 +26,22 @@
 #include <gio/gio.h>
 #include <gtk/gtk.h>
 
+#include <talkatu/talkatuformat.h>
 #include <talkatu/talkatuinput.h>
 
-#define TALKATU_ACTION_FORMAT_BOLD          ("format-bold")
-#define TALKATU_ACTION_FORMAT_ITALIC        ("format-italic")
-#define TALKATU_ACTION_FORMAT_UNDERLINE     ("format-underline")
+#define TALKATU_ACTION_FORMAT_BOLD ("format-bold")
+#define TALKATU_ACTION_FORMAT_ITALIC ("format-italic")
+#define TALKATU_ACTION_FORMAT_UNDERLINE ("format-underline")
 #define TALKATU_ACTION_FORMAT_STRIKETHROUGH ("format-strikethrough")
-#define TALKATU_ACTION_FORMAT_GROW          ("format-grow")
-#define TALKATU_ACTION_FORMAT_SHRINK        ("format-shrink")
-#define TALKATU_ACTION_FORMAT_RESET         ("format-reset")
+#define TALKATU_ACTION_FORMAT_GROW ("format-grow")
+#define TALKATU_ACTION_FORMAT_SHRINK ("format-shrink")
+#define TALKATU_ACTION_FORMAT_RESET ("format-reset")
 
-#define TALKATU_ACTION_ATTACH_FILE          ("attach-file")
+#define TALKATU_ACTION_ATTACH_FILE ("attach-file")
+#define TALKATU_ACTION_ATTACH_IMAGE ("attach-image")
 
-#define TALKATU_ACTION_INSERT_LINK          ("insert-link")
+#define TALKATU_ACTION_INSERT_LINK ("insert-link")
+#define TALKATU_ACTION_INSERT_CODE ("insert-code")
 
 G_BEGIN_DECLS
 
@@ -57,21 +60,24 @@
 	gpointer reserved[4];
 };
 
-GSimpleActionGroup *talkatu_action_group_new(GtkTextBuffer *buffer);
+GSimpleActionGroup *talkatu_action_group_new(TalkatuFormat format);
+GSimpleActionGroup *talkatu_action_group_new_with_buffer(TalkatuFormat format, GtkTextBuffer *buffer);
 
 GtkTextBuffer *talkatu_action_group_get_buffer(TalkatuActionGroup *ag);
+void talkatu_action_group_set_buffer(TalkatuActionGroup *ag, GtkTextBuffer *buffer);
 
 void talkatu_action_group_set_input(TalkatuActionGroup *ag, TalkatuInput *input);
 TalkatuInput *talkatu_action_group_get_input(TalkatuActionGroup *ag);
 
-void talkatu_action_group_enable_action(TalkatuActionGroup *ag, const gchar *name);
-
 const gchar *talkatu_action_name_for_tag_name(const gchar *tag_name);
 
 void talkatu_action_group_activate_format(TalkatuActionGroup *ag, const gchar *format_name);
 gboolean talkatu_action_group_get_action_activated(TalkatuActionGroup *ag, const gchar *name);
 gchar **talkatu_action_group_get_activated_formats(TalkatuActionGroup *ag);
 
+TalkatuFormat talkatu_action_group_get_format(TalkatuActionGroup *ag);
+void talkatu_action_group_set_format(TalkatuActionGroup *ag, TalkatuFormat format);
+
 G_END_DECLS
 
 #endif /* TALKATU_ACTIONGROUP_H */
diff --git a/talkatu/talkatuactiongroup.c b/talkatu/talkatuactiongroup.c
--- a/talkatu/talkatuactiongroup.c
+++ b/talkatu/talkatuactiongroup.c
@@ -1,6 +1,6 @@
 /*
  * Talkatu - GTK widgets for chat applications
- * Copyright (C) 2017-2020 Gary Kramlich <grim@reaperworld.com>
+ * Copyright (C) 2017-2023 Gary Kramlich <grim@reaperworld.com>
  *
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
 #include "talkatu/talkatuattachment.h"
 #include "talkatu/talkatuattachmentdialog.h"
 #include "talkatu/talkatubuffer.h"
+#include "talkatu/talkatuenums.h"
 #include "talkatu/talkatulinkdialog.h"
 #include "talkatu/talkatumarkup.h"
 #include "talkatu/talkatumessage.h"
@@ -101,12 +102,14 @@
 
 typedef struct {
 	GtkTextBuffer *buffer;
+	TalkatuFormat format;
 	TalkatuInput *input;
 } TalkatuActionGroupPrivate;
 
 enum {
 	PROP_0,
 	PROP_BUFFER,
+	PROP_FORMAT,
 	PROP_INPUT,
 	N_PROPERTIES
 };
@@ -123,13 +126,29 @@
 /******************************************************************************
  * Helpers
  *****************************************************************************/
-static void
-talkatu_action_group_set_buffer(TalkatuActionGroup *ag, GtkTextBuffer *buffer) {
-	TalkatuActionGroupPrivate *priv = talkatu_action_group_get_instance_private(ag);
+/*
+ * talkatu_action_group_set_action_enabled:
+ * @ag: The TalkatuActionGroup
+ * @action_name: The name of the action.
+ * @enabled: Whether or not not enable the action.
+ *
+ * Looks up the action with @action_name in @ag and sets it's enabled property
+ * to @enabled.
+ */
+static inline void
+talkatu_action_group_set_action_enabled(TalkatuActionGroup *ag,
+                                        const char *name,
+                                        gboolean enabled)
+{
+	GAction *action = NULL;
 
-	g_return_if_fail(TALKATU_IS_BUFFER(buffer));
+	g_return_if_fail(TALKATU_IS_ACTION_GROUP(ag));
+	g_return_if_fail(name != NULL);
 
-	g_set_object(&priv->buffer, buffer);
+	action = g_action_map_lookup_action(G_ACTION_MAP(ag), name);
+	if(G_IS_SIMPLE_ACTION(action)) {
+		g_simple_action_set_enabled(G_SIMPLE_ACTION(action), enabled);
+	}
 }
 
 static void
@@ -199,7 +218,6 @@
                         gpointer       user_data)
 {
 	g_message(_("activating action %s"), g_action_get_name(G_ACTION(action)));
-
 }
 
 static void
@@ -523,6 +541,9 @@
 		case PROP_BUFFER:
 			g_value_set_object(value, talkatu_action_group_get_buffer(ag));
 			break;
+		case PROP_FORMAT:
+			g_value_set_flags(value, talkatu_action_group_get_format(ag));
+			break;
 		case PROP_INPUT:
 			g_value_set_object(value, talkatu_action_group_get_input(ag));
 			break;
@@ -544,6 +565,9 @@
 		case PROP_BUFFER:
 			talkatu_action_group_set_buffer(ag, g_value_get_object(value));
 			break;
+		case PROP_FORMAT:
+			talkatu_action_group_set_format(ag, g_value_get_flags(value));
+			break;
 		case PROP_INPUT:
 			talkatu_action_group_set_input(ag, g_value_get_object(value));
 			break;
@@ -657,10 +681,24 @@
 	properties[PROP_BUFFER] = g_param_spec_object(
 		"buffer", "buffer", "The buffer to work on",
 		TALKATU_TYPE_BUFFER,
-		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
 	);
 
 	/**
+	 * TalkatuActionGroup::format:
+	 *
+	 * The [flags@Talkatu.Format] to use to set which actions are enabled.
+	 *
+	 * Since: 0.2.0
+	 */
+	properties[PROP_FORMAT] = g_param_spec_flags(
+		"format", "format",
+		"The format options to enable",
+		TALKATU_TYPE_FORMAT,
+		TALKATU_FORMAT_NONE,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
 	 * TalkatuActionGroup::input:
 	 *
 	 * The #TalkatuInput that this action group is tied to.
@@ -713,10 +751,22 @@
  * Returns: (transfer full): The new #TalkatuActionGroup instance.
  */
 GSimpleActionGroup *
-talkatu_action_group_new(GtkTextBuffer *buffer) {
+talkatu_action_group_new(TalkatuFormat format) {
+	return g_object_new(
+		TALKATU_TYPE_ACTION_GROUP,
+		"format", format,
+		NULL
+	);
+}
+
+GSimpleActionGroup *
+talkatu_action_group_new_with_buffer(TalkatuFormat format,
+                                     GtkTextBuffer *buffer)
+{
 	return g_object_new(
 		TALKATU_TYPE_ACTION_GROUP,
 		"buffer", buffer,
+		"format", format,
 		NULL
 	);
 }
@@ -742,6 +792,24 @@
 }
 
 /**
+ * talkatu_action_group_set_buffer:
+ * @ag: The instance.
+ * @buffer: The buffer to use.
+ *
+ * Sets the [class@Gtk.TextBuffer] that @ag should use.
+ *
+ * Since: 0.2.0
+ */
+void
+talkatu_action_group_set_buffer(TalkatuActionGroup *ag, GtkTextBuffer *buffer) {
+	TalkatuActionGroupPrivate *priv = talkatu_action_group_get_instance_private(ag);
+
+	g_return_if_fail(TALKATU_IS_BUFFER(buffer));
+
+	g_set_object(&priv->buffer, buffer);
+}
+
+/**
  * talkatu_action_group_set_input:
  * @ag: The #TalkatuActionGroup instance.
  * @input: A #TalkatuInput instance or %NULL.
@@ -780,27 +848,6 @@
 }
 
 /**
- * talkatu_action_group_enable_action:
- * @ag: The #TalkatuActionGroup instance.
- * @name: The name of the action to enable.
- *
- * By default a #TalkatuActionGroup's actions are all disabled.  To enable them
- * you must call this function one at time.
- */
-void
-talkatu_action_group_enable_action(TalkatuActionGroup *ag, const gchar *name) {
-	GAction *action = NULL;
-
-	g_return_if_fail(TALKATU_IS_ACTION_GROUP(ag));
-	g_return_if_fail(name != NULL);
-
-	action = g_action_map_lookup_action(G_ACTION_MAP(ag), name);
-	if(action != NULL) {
-		g_simple_action_set_enabled(G_SIMPLE_ACTION(action), TRUE);
-	}
-}
-
-/**
  * talkatu_action_name_for_tag_name:
  * @tag_name: The name of the tag to lookup.
  *
@@ -920,3 +967,86 @@
 
 	return ret;
 }
+
+/**
+ * talkatu_action_group_get_format:
+ * @ag: The instance.
+ *
+ * Gets the [flags@Talkatu.Format] that @ag current has enabled.
+ *
+ * Returns: The format options that are enabled.
+ *
+ * Since: 0.2.0
+ */
+TalkatuFormat
+talkatu_action_group_get_format(TalkatuActionGroup *ag) {
+	TalkatuActionGroupPrivate *priv = NULL;
+
+	g_return_val_if_fail(TALKATU_IS_ACTION_GROUP(ag), TALKATU_FORMAT_NONE);
+
+	priv = talkatu_action_group_get_instance_private(ag);
+
+	return priv->format;
+}
+
+/**
+ * talkatu_action_group_set_format:
+ * @ag: The instance.
+ * @format: The [flags@Talkatu.Format] to set as enabled.
+ *
+ * Sets the enabled actions of @ag to @format.
+ *
+ * Since: 0.2.0
+ */
+void
+talkatu_action_group_set_format(TalkatuActionGroup *ag, TalkatuFormat format) {
+	gboolean enabled = FALSE;
+
+	g_return_if_fail(TALKATU_IS_ACTION_GROUP(ag));
+
+	enabled = ((format & TALKATU_FORMAT_BOLD) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_FORMAT_BOLD,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_ITALIC) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_FORMAT_ITALIC,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_UNDERLINE) != 0);
+	talkatu_action_group_set_action_enabled(ag,
+	                                        TALKATU_ACTION_FORMAT_UNDERLINE,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_STRIKETHROUGH) != 0);
+	talkatu_action_group_set_action_enabled(ag,
+	                                        TALKATU_ACTION_FORMAT_STRIKETHROUGH,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_GROW) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_FORMAT_GROW,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_SHRINK) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_FORMAT_SHRINK,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_RESET) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_FORMAT_RESET,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_ATTACH_FILE) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_ATTACH_FILE,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_ATTACH_IMAGE) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_ATTACH_IMAGE,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_INSERT_LINK) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_INSERT_LINK,
+	                                        enabled);
+
+	enabled = ((format & TALKATU_FORMAT_INSERT_CODE) != 0);
+	talkatu_action_group_set_action_enabled(ag, TALKATU_ACTION_INSERT_CODE,
+	                                        enabled);
+}
diff --git a/talkatu/talkatubuffer.h b/talkatu/talkatubuffer.h
--- a/talkatu/talkatubuffer.h
+++ b/talkatu/talkatubuffer.h
@@ -46,8 +46,6 @@
 	/*< public >*/
 	void (*insert_markup)(TalkatuBuffer *buffer, GtkTextIter *pos, const gchar *new_text, gint new_text_length);
 
-	GSimpleActionGroup *(*create_action_group)(TalkatuBuffer *buffer);
-
 	/*< private >*/
 	gpointer reserved[4];
 };
@@ -55,7 +53,9 @@
 GtkTextBuffer *talkatu_buffer_new(GSimpleActionGroup *action_group);
 
 TalkatuBufferStyle talkatu_buffer_get_style(TalkatuBuffer *buffer);
+
 GSimpleActionGroup *talkatu_buffer_get_action_group(TalkatuBuffer *buffer);
+void talkatu_buffer_set_action_group(TalkatuBuffer *buffer, GSimpleActionGroup *group);
 
 void talkatu_buffer_insert_markup(TalkatuBuffer *buffer, GtkTextIter *pos, const gchar *new_text, gint new_text_length);
 void talkatu_buffer_insert_markup_with_tags_by_name(TalkatuBuffer *buffer, GtkTextIter *pos, const gchar *new_text, gint new_text_length, const gchar *first_tag_name, ...);
diff --git a/talkatu/talkatubuffer.c b/talkatu/talkatubuffer.c
--- a/talkatu/talkatubuffer.c
+++ b/talkatu/talkatubuffer.c
@@ -121,11 +121,6 @@
 	);
 }
 
-static GSimpleActionGroup *
-talkatu_buffer_default_creation_action_group(TalkatuBuffer *buffer) {
-	return g_simple_action_group_new();
-}
-
 /******************************************************************************
  * GtkTextBuffer Stuff
  *****************************************************************************/
@@ -266,40 +261,6 @@
 	g_object_notify(G_OBJECT(buffer), "style");
 }
 
-static void
-talkatu_buffer_set_action_group(TalkatuBuffer *buffer,
-                                GSimpleActionGroup *action_group)
-{
-	TalkatuBufferPrivate *priv = talkatu_buffer_get_instance_private(buffer);
-
-	/* clear the tags */
-	g_slist_free(priv->tags);
-	priv->tags = NULL;
-
-	/* clean up the old one */
-	if(priv->action_group) {
-		g_signal_handlers_disconnect_by_func(
-			priv->action_group,
-			talkatu_buffer_action_toggled_cb,
-			buffer
-		);
-
-		g_object_unref(G_OBJECT(priv->action_group));
-
-		priv->action_group = NULL;
-	}
-
-	if(G_IS_SIMPLE_ACTION_GROUP(action_group)) {
-		priv->action_group = g_object_ref(action_group);
-		g_signal_connect(
-			action_group,
-			"action-state-changed",
-			G_CALLBACK(talkatu_buffer_action_toggled_cb),
-			buffer
-		);
-	}
-}
-
 /******************************************************************************
  * GObject Stuff
  *****************************************************************************/
@@ -394,7 +355,6 @@
 	text_buffer_class->mark_set = talkatu_buffer_mark_set;
 
 	klass->insert_markup = talkatu_buffer_real_insert_markup;
-	klass->create_action_group = talkatu_buffer_default_creation_action_group;
 
 	properties[PROP_STYLE] = g_param_spec_enum(
 		"style", "style", "The format style of the buffer",
@@ -472,19 +432,56 @@
 
 	priv = talkatu_buffer_get_instance_private(buffer);
 
-	if(priv->action_group == NULL) {
-		TalkatuBufferClass *klass = TALKATU_BUFFER_GET_CLASS(buffer);
-		GSimpleActionGroup *action_group = NULL;
+	return priv->action_group;
+}
+
+/**
+ * talkatu_buffer_set_action_group:
+ * @buffer: The instance.
+ * @action_group: The new action group.
+ *
+ * Sets the [class@Gio.SimpleActionGroup] of @buffer to @action_group.
+ * @action_group is used to determine what formatting tags are current enabled
+ * among other things.
+ *
+ * Since: 0.2.0
+ */
+void
+talkatu_buffer_set_action_group(TalkatuBuffer *buffer,
+                                GSimpleActionGroup *action_group)
+{
+	TalkatuBufferPrivate *priv = NULL;
 
-		g_return_val_if_fail(klass != NULL, NULL);
-		g_return_val_if_fail(klass->create_action_group != NULL, NULL);
+	g_return_if_fail(TALKATU_IS_BUFFER(buffer));
+
+	priv = talkatu_buffer_get_instance_private(buffer);
+
+	/* clear the tags */
+	g_slist_free(priv->tags);
+	priv->tags = NULL;
 
-		action_group = klass->create_action_group(buffer);
-		talkatu_buffer_set_action_group(buffer, action_group);
-		g_object_unref(G_OBJECT(action_group));
+	/* clean up the old one */
+	if(priv->action_group) {
+		g_signal_handlers_disconnect_by_func(
+			priv->action_group,
+			talkatu_buffer_action_toggled_cb,
+			buffer
+		);
+
+		g_object_unref(G_OBJECT(priv->action_group));
+
+		priv->action_group = NULL;
 	}
 
-	return priv->action_group;
+	if(G_IS_SIMPLE_ACTION_GROUP(action_group)) {
+		priv->action_group = g_object_ref(action_group);
+		g_signal_connect(
+			action_group,
+			"action-state-changed",
+			G_CALLBACK(talkatu_buffer_action_toggled_cb),
+			buffer
+		);
+	}
 }
 
 /**
diff --git a/talkatu/talkatuformat.h b/talkatu/talkatuformat.h
new file mode 100644
--- /dev/null
+++ b/talkatu/talkatuformat.h
@@ -0,0 +1,81 @@
+/*
+ * Talkatu - GTK widgets for chat applications
+ * Copyright (C) 2017-2023 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(TALKATU_GLOBAL_HEADER_INSIDE) && !defined(TALKATU_COMPILATION)
+#error "only <talkatu.h> may be included directly"
+#endif
+
+#ifndef TALKATU_FORMAT_H
+#define TALKATU_FORMAT_H
+
+#include <glib.h>
+
+typedef enum {
+	TALKATU_FORMAT_NONE = 0,
+	TALKATU_FORMAT_BOLD = 1 << 0,
+	TALKATU_FORMAT_ITALIC = 1 << 1,
+	TALKATU_FORMAT_UNDERLINE = 1 << 2,
+	TALKATU_FORMAT_STRIKETHROUGH = 1 << 3,
+	TALKATU_FORMAT_GROW = 1 << 4,
+	TALKATU_FORMAT_SHRINK = 1 << 5,
+	TALKATU_FORMAT_RESET = 1 << 6,
+	TALKATU_FORMAT_ATTACH_FILE = 1 << 7,
+	TALKATU_FORMAT_ATTACH_IMAGE = 1 << 8,
+	TALKATU_FORMAT_INSERT_LINK = 1 << 9,
+	TALKATU_FORMAT_INSERT_CODE = 1 << 10,
+	/* Helper presets. */
+	TALKATU_FORMAT_HTML = TALKATU_FORMAT_BOLD |
+	                      TALKATU_FORMAT_ITALIC |
+	                      TALKATU_FORMAT_UNDERLINE |
+	                      TALKATU_FORMAT_STRIKETHROUGH |
+	                      TALKATU_FORMAT_GROW |
+	                      TALKATU_FORMAT_SHRINK |
+	                      TALKATU_FORMAT_RESET |
+	                      TALKATU_FORMAT_ATTACH_FILE |
+	                      TALKATU_FORMAT_ATTACH_IMAGE |
+	                      TALKATU_FORMAT_INSERT_LINK |
+	                      /* g-ir-scanner has issues with the last element
+	                       * on a line by itself, so we trick it by or'n the
+	                       * last item with a 0.
+	                       *
+	                       * see https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/454
+	                       */
+	                      TALKATU_FORMAT_INSERT_CODE | 0,
+	TALKATU_FORMAT_MARKDOWN = TALKATU_FORMAT_BOLD |
+	                          TALKATU_FORMAT_ITALIC |
+	                          TALKATU_FORMAT_UNDERLINE |
+	                          TALKATU_FORMAT_STRIKETHROUGH |
+	                          TALKATU_FORMAT_RESET |
+	                          TALKATU_FORMAT_ATTACH_FILE |
+	                          TALKATU_FORMAT_ATTACH_IMAGE |
+	                          TALKATU_FORMAT_INSERT_LINK |
+	                          /* g-ir-scanner has issues with the last element
+	                           * on a line by itself, so we trick it by or'n
+	                           * the last item with a 0.
+	                           *
+	                           * see https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/454
+	                           */
+	                          TALKATU_FORMAT_INSERT_CODE | 0,
+} TalkatuFormat;
+
+G_BEGIN_DECLS
+
+
+G_END_DECLS
+
+#endif /* TALKATU_FORMAT_H */
diff --git a/talkatu/talkatuhtmlbuffer.h b/talkatu/talkatuhtmlbuffer.h
deleted file mode 100644
--- a/talkatu/talkatuhtmlbuffer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Talkatu - GTK widgets for chat applications
- * Copyright (C) 2017-2020 Gary Kramlich <grim@reaperworld.com>
- *
- * This library 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 2 of the License, or
- * (at your option) any later version.
- *
- * This library 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(TALKATU_GLOBAL_HEADER_INSIDE) && !defined(TALKATU_COMPILATION)
-#error "only <talkatu.h> may be included directly"
-#endif
-
-#ifndef TALKATU_HTML_BUFFER_H
-#define TALKATU_HTML_BUFFER_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <gtk/gtk.h>
-
-#include "talkatu/talkatubuffer.h"
-
-G_BEGIN_DECLS
-
-#define TALKATU_TYPE_HTML_BUFFER            (talkatu_html_buffer_get_type())
-
-G_DECLARE_DERIVABLE_TYPE(TalkatuHtmlBuffer, talkatu_html_buffer, TALKATU, HTML_BUFFER, TalkatuBuffer)
-
-struct _TalkatuHtmlBufferClass {
-	/*< private >*/
-	TalkatuBufferClass parent;
-
-	/*< public >*/
-	void (*insert_html)(TalkatuHtmlBuffer *buffer, GtkTextIter *iter, const gchar *text, gint len);
-
-	/*< private >*/
-	gpointer reserved[4];
-};
-
-GtkTextBuffer *talkatu_html_buffer_new(void);
-
-void talkatu_html_buffer_insert_html(TalkatuHtmlBuffer *buffer, GtkTextIter *iter, const gchar *text, gint len);
-
-G_END_DECLS
-
-#endif /* TALKATU_HTML_BUFFER_H */
diff --git a/talkatu/talkatuhtmlbuffer.c b/talkatu/talkatuhtmlbuffer.c
deleted file mode 100644
--- a/talkatu/talkatuhtmlbuffer.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Talkatu - GTK widgets for chat applications
- * Copyright (C) 2017-2020 Gary Kramlich <grim@reaperworld.com>
- *
- * This library 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 2 of the License, or
- * (at your option) any later version.
- *
- * This library 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "talkatu/talkatuactiongroup.h"
-#include "talkatu/talkatubuffer.h"
-#include "talkatu/talkatucodeset.h"
-#include "talkatu/talkatuhtmlbuffer.h"
-#include "talkatu/talkatumarkup.h"
-#include "talkatu/talkatutag.h"
-#include "talkatu/talkatutagtable.h"
-
-/**
- * TalkatuHtmlBuffer:
- *
- * A #TalkatuBuffer subclass that renders HTML.
- */
-
-/**
- * TalkatuHtmlBufferClass:
- * @insert_html: The insert_html vfunc is called to render HTML into the
- *               #TalkatuHtmlBuffer.
- *
- * The backing class to #TalkatuHtmlBuffer.
- */
-
-G_DEFINE_TYPE(TalkatuHtmlBuffer, talkatu_html_buffer, TALKATU_TYPE_BUFFER);
-
-/******************************************************************************
- * TalkatuBuffer Stuff
- *****************************************************************************/
-static GSimpleActionGroup *
-talkatu_html_buffer_create_action_group(TalkatuBuffer *buffer) {
-	GSimpleActionGroup *ag = talkatu_action_group_new(GTK_TEXT_BUFFER(buffer));
-
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_BOLD);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_ITALIC);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_UNDERLINE);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_STRIKETHROUGH);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_SHRINK);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_GROW);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_RESET);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_ATTACH_FILE);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_INSERT_LINK);
-
-	return ag;
-}
-
-/******************************************************************************
- * GObject Stuff
- *****************************************************************************/
-static void
-talkatu_html_buffer_init(TalkatuHtmlBuffer *buffer) {
-	// gtk_text_buffer_register_deserialize_format(
-	// 	GTK_TEXT_BUFFER(buffer),
-	// 	"text/html",
-	// 	talkatu_markup_deserialize_html,
-	// 	NULL,
-	// 	NULL
-	// );
-
-	// gtk_text_buffer_register_serialize_format(
-	// 	GTK_TEXT_BUFFER(buffer),
-	// 	"text/html",
-	// 	talkatu_markup_serialize_html,
-	// 	NULL,
-	// 	NULL
-	// );
-}
-
-static void
-talkatu_html_buffer_class_init(TalkatuHtmlBufferClass *klass) {
-	TalkatuBufferClass *buffer_class = TALKATU_BUFFER_CLASS(klass);
-
-	buffer_class->create_action_group = talkatu_html_buffer_create_action_group;
-}
-
-/******************************************************************************
- * Public API
- *****************************************************************************/
-
-/**
- * talkatu_html_buffer_new:
- *
- * Creates a new #TalkatuHtmlBuffer.  A #TalkatuHtmlBuffer supports HTML
- * formatting as well as pasting rendered HTML.
- *
- * Returns: (transfer full): The new #TalkatuHtmlBuffer instance.
- */
-GtkTextBuffer *talkatu_html_buffer_new(void) {
-	return GTK_TEXT_BUFFER(g_object_new(
-		TALKATU_TYPE_HTML_BUFFER,
-		"tag-table", talkatu_tag_table_new(),
-		NULL
-	));
-}
-
-/**
- * talkatu_html_buffer_insert_html:
- * @buffer: The #TalkatuHtmlBuffer instance.
- * @iter: The #GtkTextIter where to insert the HTML.
- * @text: The HTML text to insert.
- * @len: The length of @text or -1
- *
- * Inserts and renders @text as HTML into @buffer.
- */
-void
-talkatu_html_buffer_insert_html(TalkatuHtmlBuffer *buffer,
-                                GtkTextIter *iter,
-                                const gchar *text,
-                                gint len)
-{
-	g_return_if_fail(TALKATU_IS_HTML_BUFFER(buffer));
-	g_return_if_fail(iter != NULL);
-	g_return_if_fail(text != NULL);
-
-	talkatu_markup_insert_html(TALKATU_BUFFER(buffer), iter, text, len);
-}
diff --git a/talkatu/talkatumarkdownbuffer.h b/talkatu/talkatumarkdown.h
rename from talkatu/talkatumarkdownbuffer.h
rename to talkatu/talkatumarkdown.h
--- a/talkatu/talkatumarkdownbuffer.h
+++ b/talkatu/talkatumarkdown.h
@@ -1,6 +1,6 @@
 /*
  * Talkatu - GTK widgets for chat applications
- * Copyright (C) 2017-2020 Gary Kramlich <grim@reaperworld.com>
+ * Copyright (C) 2017-2023 Gary Kramlich <grim@reaperworld.com>
  *
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,11 +20,10 @@
 #error "only <talkatu.h> may be included directly"
 #endif
 
-#ifndef TALKATU_MARKDOWN_BUFFER_H
-#define TALKATU_MARKDOWN_BUFFER_H
+#ifndef TALKATU_MARKDOWN_H
+#define TALKATU_MARKDOWN_H
 
 #include <glib.h>
-#include <glib-object.h>
 
 #include <gtk/gtk.h>
 
@@ -32,25 +31,8 @@
 
 G_BEGIN_DECLS
 
-#define TALKATU_TYPE_MARKDOWN_BUFFER            (talkatu_markdown_buffer_get_type())
-
-G_DECLARE_DERIVABLE_TYPE(TalkatuMarkdownBuffer, talkatu_markdown_buffer, TALKATU, MARKDOWN_BUFFER, TalkatuBuffer)
-
-struct _TalkatuMarkdownBufferClass {
-	/*< private >*/
-	TalkatuBufferClass parent;
-
-	/*< public >*/
-	void (*insert_markdown)(TalkatuMarkdownBuffer *buffer, GtkTextIter *iter, const gchar *text, gint len);
-
-	/*< private >*/
-	gpointer reserved[4];
-};
-
-GtkTextBuffer *talkatu_markdown_buffer_new(void);
-
-void talkatu_markdown_buffer_insert_markdown(TalkatuMarkdownBuffer *buffer, GtkTextIter *iter, const gchar *text, gint len);
+void talkatu_markdown_insert(TalkatuBuffer *buffer, GtkTextIter *iter, const gchar *text, gint len);
 
 G_END_DECLS
 
-#endif /* TALKATU_MARKDOWN_BUFFER_H */
+#endif /* TALKATU_MARKDOWN_H */
diff --git a/talkatu/talkatumarkdownbuffer.c b/talkatu/talkatumarkdown.c
rename from talkatu/talkatumarkdownbuffer.c
rename to talkatu/talkatumarkdown.c
--- a/talkatu/talkatumarkdownbuffer.c
+++ b/talkatu/talkatumarkdown.c
@@ -1,6 +1,6 @@
 /*
  * Talkatu - GTK widgets for chat applications
- * Copyright (C) 2017-2020 Gary Kramlich <grim@reaperworld.com>
+ * Copyright (C) 2017-2023 Gary Kramlich <grim@reaperworld.com>
  *
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,26 +21,10 @@
 #include "talkatu/talkatuactiongroup.h"
 #include "talkatu/talkatubuffer.h"
 #include "talkatu/talkatucodeset.h"
-#include "talkatu/talkatumarkdownbuffer.h"
+#include "talkatu/talkatumarkdown.h"
 #include "talkatu/talkatutag.h"
 #include "talkatu/talkatutagtable.h"
 
-/**
- * TalkatuMarkdownBuffer:
- *
- * A #TalkatuBuffer subclass that renders markdown.
- */
-
-/**
- * TalkatuMarkdownBufferClass:
- * @insert_markdown: The insert_markdown vfunc is called to render
- *                   markdown into the #TalkatuMarkdownBuffer.
- *
- * The backing class for #TalkatuMarkdownBuffer.
- */
-
-G_DEFINE_TYPE(TalkatuMarkdownBuffer, talkatu_markdown_buffer, TALKATU_TYPE_BUFFER);
-
 /******************************************************************************
  * Helpers
  *****************************************************************************/
@@ -67,12 +51,8 @@
 		return FALSE;
 	}
 
-	talkatu_markdown_buffer_insert_markdown(
-		TALKATU_MARKDOWN_BUFFER(register_buffer),
-		iter,
-		text,
-		text_length
-	);
+	talkatu_markdown_insert(TALKATU_BUFFER(register_buffer), iter, text,
+	                        text_length);
 
 	g_free(text);
 
@@ -111,18 +91,32 @@
 /******************************************************************************
  * TalkatuMarkdownBuffer Stuff
  *****************************************************************************/
-static void
-talkatu_markdown_buffer_real_insert_markdown(TalkatuMarkdownBuffer *buffer,
-                                             GtkTextIter *iter,
-                                             const gchar *text,
-                                             gint len)
+
+/**
+ * talkatu_markdown_insert:
+ * @buffer: The #TalkatuMarkdownBuffer instance.
+ * @iter: The #GtkTextIter where the text should be inserted.
+ * @text: The UTF-8 Markdown text that should be inserted.
+ * @len: The length of @text or -1.
+ *
+ * Inserts and renders @text into @buffer.
+ */
+void
+talkatu_markdown_insert(TalkatuBuffer *buffer, GtkTextIter *iter,
+                        const gchar *text, gint len)
 {
-	GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table(GTK_TEXT_BUFFER(buffer));
+	GtkTextTagTable *tag_table = NULL;
 	gint start_offset = -1;
 	cmark_node *root = NULL;
 	cmark_iter *mditer = NULL;
 	cmark_event_type ev_type;
 
+	g_return_if_fail(TALKATU_IS_BUFFER(buffer));
+	g_return_if_fail(iter != NULL);
+	g_return_if_fail(text != NULL);
+
+	tag_table = gtk_text_buffer_get_tag_table(GTK_TEXT_BUFFER(buffer));
+
 	root = cmark_parse_document(text, len, CMARK_OPT_HARDBREAKS | CMARK_OPT_SAFE);
 	mditer = cmark_iter_new(root);
 
@@ -244,90 +238,3 @@
 	cmark_iter_free(mditer);
 	cmark_node_free(root);
 }
-
-/******************************************************************************
- * TalkatuBuffer Stuff
- *****************************************************************************/
-static GSimpleActionGroup *
-talkatu_markdown_buffer_create_action_group(TalkatuBuffer *buffer) {
-	GSimpleActionGroup *ag = talkatu_action_group_new(GTK_TEXT_BUFFER(buffer));
-
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_BOLD);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_ITALIC);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_UNDERLINE);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_STRIKETHROUGH);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_RESET);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_ATTACH_FILE);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_INSERT_LINK);
-
-	return ag;
-}
-
-/******************************************************************************
- * GObject Stuff
- *****************************************************************************/
-static void
-talkatu_markdown_buffer_init(TalkatuMarkdownBuffer *buffer) {
-	// gtk_text_buffer_register_deserialize_format(
-	// 	GTK_TEXT_BUFFER(buffer),
-	// 	"text/markdown",
-	// 	talkatu_markdown_buffer_deserialize_markdown,
-	// 	NULL,
-	// 	NULL
-	// );
-}
-
-static void
-talkatu_markdown_buffer_class_init(TalkatuMarkdownBufferClass *klass) {
-	TalkatuBufferClass *buffer_class = TALKATU_BUFFER_CLASS(klass);
-
-	buffer_class->create_action_group = talkatu_markdown_buffer_create_action_group;
-
-	klass->insert_markdown = talkatu_markdown_buffer_real_insert_markdown;
-}
-
-/******************************************************************************
- * Public API
- *****************************************************************************/
-
-/**
- * talkatu_markdown_buffer_new:
- *
- * Creates a new #TalkatuMarkdownBuffer that can render Markdown.
- *
- * Returns: (transfer full): The new #TalkatuMarkdownBuffer.
- */
-GtkTextBuffer *talkatu_markdown_buffer_new(void) {
-	return GTK_TEXT_BUFFER(g_object_new(
-		TALKATU_TYPE_MARKDOWN_BUFFER,
-		"tag-table", talkatu_tag_table_new(),
-		NULL
-	));
-}
-
-/**
- * talkatu_markdown_buffer_insert_markdown:
- * @buffer: The #TalkatuMarkdownBuffer instance.
- * @iter: The #GtkTextIter where the text should be inserted.
- * @text: The UTF-8 Markdown text that should be inserted.
- * @len: The length of @text or -1.
- *
- * Inserts and renders @text into @buffer.
- */
-void
-talkatu_markdown_buffer_insert_markdown(TalkatuMarkdownBuffer *buffer,
-                                        GtkTextIter *iter,
-                                        const gchar *text,
-                                        gint len)
-{
-	TalkatuMarkdownBufferClass *klass = NULL;
-
-	g_return_if_fail(TALKATU_IS_MARKDOWN_BUFFER(buffer));
-	g_return_if_fail(iter != NULL);
-	g_return_if_fail(text != NULL);
-
-	klass = TALKATU_MARKDOWN_BUFFER_GET_CLASS(buffer);
-	if(klass && klass->insert_markdown) {
-		klass->insert_markdown(buffer, iter, text, len);
-	}
-}
diff --git a/talkatu/talkatuwholebuffer.h b/talkatu/talkatuwholebuffer.h
deleted file mode 100644
--- a/talkatu/talkatuwholebuffer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Talkatu - GTK widgets for chat applications
- * Copyright (C) 2017-2020 Gary Kramlich <grim@reaperworld.com>
- *
- * This library 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 2 of the License, or
- * (at your option) any later version.
- *
- * This library 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(TALKATU_GLOBAL_HEADER_INSIDE) && !defined(TALKATU_COMPILATION)
-#error "only <talkatu.h> may be included directly"
-#endif
-
-#ifndef TALKATU_WHOLE_BUFFER_H
-#define TALKATU_WHOLE_BUFFER_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <gtk/gtk.h>
-
-#include <talkatu/talkatubuffer.h>
-
-G_BEGIN_DECLS
-
-#define TALKATU_TYPE_WHOLE_BUFFER            (talkatu_whole_buffer_get_type())
-
-G_DECLARE_FINAL_TYPE(TalkatuWholeBuffer, talkatu_whole_buffer, TALKATU, WHOLE_BUFFER, TalkatuBuffer)
-
-GtkTextBuffer *talkatu_whole_buffer_new(void);
-
-G_END_DECLS
-
-#endif /* TALKATU_WHOLE_BUFFER_H */
diff --git a/talkatu/talkatuwholebuffer.c b/talkatu/talkatuwholebuffer.c
deleted file mode 100644
--- a/talkatu/talkatuwholebuffer.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Talkatu - GTK widgets for chat applications
- * Copyright (C) 2017-2020 Gary Kramlich <grim@reaperworld.com>
- *
- * This library 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 2 of the License, or
- * (at your option) any later version.
- *
- * This library 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include <gtk/gtk.h>
-
-#include "talkatu/talkatuactiongroup.h"
-#include "talkatu/talkatuwholebuffer.h"
-
-/**
- * TalkatuWholeBuffer:
- *
- * A #TalkatuBuffer subclass that applies formatting to the entire buffer
- * rather that allowing rich formatting at character resolution.
- */
-struct _TalkatuWholeBuffer {
-	TalkatuBuffer parent;
-};
-
-G_DEFINE_TYPE(TalkatuWholeBuffer, talkatu_whole_buffer, TALKATU_TYPE_BUFFER)
-
-/******************************************************************************
- * TalkatuBuffer Stuff
- *****************************************************************************/
-static GSimpleActionGroup *
-talkatu_whole_buffer_create_action_group(TalkatuBuffer *buffer) {
-	GSimpleActionGroup *ag = talkatu_action_group_new(GTK_TEXT_BUFFER(buffer));
-
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_BOLD);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_ITALIC);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_UNDERLINE);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_STRIKETHROUGH);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_SHRINK);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_GROW);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_RESET);
-	talkatu_action_group_enable_action(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_INSERT_LINK);
-
-	return ag;
-}
-
-/******************************************************************************
- * GObject Stuff
- *****************************************************************************/
-static GObject *
-talkatu_whole_buffer_constructor(GType type,
-                                 guint n_params,
-                                 GObjectConstructParam *params)
-{
-	GObjectConstructParam *param;
-	gint i = 0;
-
-	for(i = 0, param = params; i < n_params; i++, param++) {
-		const gchar *name = g_param_spec_get_name(param->pspec);
-		if(g_ascii_strcasecmp("style", name) == 0) {
-			g_value_set_enum(param->value, TALKATU_BUFFER_STYLE_WHOLE);
-		}
-	}
-
-	return G_OBJECT_CLASS(talkatu_whole_buffer_parent_class)->constructor(type, n_params, params);
-}
-
-static void
-talkatu_whole_buffer_init(TalkatuWholeBuffer *whole_buffer) {
-}
-
-static void
-talkatu_whole_buffer_class_init(TalkatuWholeBufferClass *klass) {
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-	TalkatuBufferClass *buffer_class = TALKATU_BUFFER_CLASS(klass);
-
-	obj_class->constructor = talkatu_whole_buffer_constructor;
-
-	buffer_class->create_action_group = talkatu_whole_buffer_create_action_group;
-}
-
-/******************************************************************************
- * Public API
- *****************************************************************************/
-
-/**
- * talkatu_whole_buffer_new:
- *
- * Creates a new #TalkatuWholeBuffer that applies formatting across the whole
- * text buffer instead of just a subset.
- *
- * Returns: (transfer full): The new #TalkatuWholeBuffer instance.
- */
-GtkTextBuffer *talkatu_whole_buffer_new(void) {
-	return GTK_TEXT_BUFFER(g_object_new(
-		TALKATU_TYPE_WHOLE_BUFFER,
-		"style", TALKATU_BUFFER_STYLE_WHOLE,
-		NULL
-	));
-}
diff --git a/talkatu/tests/talkatutestactiongroup.c b/talkatu/tests/talkatutestactiongroup.c
--- a/talkatu/tests/talkatutestactiongroup.c
+++ b/talkatu/tests/talkatutestactiongroup.c
@@ -20,10 +20,14 @@
 
 static void
 talkatu_test_action_group_activate_simple(void) {
-	GtkTextBuffer *buffer = talkatu_whole_buffer_new();
-	GSimpleActionGroup *ag = talkatu_buffer_get_action_group(TALKATU_BUFFER(buffer));
+	GSimpleActionGroup *ag = NULL;
+	GtkTextBuffer *buffer = NULL;
 	gchar **activated = NULL;
 
+	ag = talkatu_action_group_new(TALKATU_FORMAT_HTML);
+	buffer = talkatu_buffer_new(ag);
+	talkatu_action_group_set_buffer(TALKATU_ACTION_GROUP(ag), buffer);
+
 	talkatu_action_group_activate_format(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_BOLD);
 
 	activated = talkatu_action_group_get_activated_formats(TALKATU_ACTION_GROUP(ag));
@@ -38,10 +42,14 @@
 
 static void
 talkatu_test_action_group_activate_multiple(void) {
-	GtkTextBuffer *buffer = talkatu_whole_buffer_new();
-	GSimpleActionGroup *ag = talkatu_buffer_get_action_group(TALKATU_BUFFER(buffer));
+	GSimpleActionGroup *ag = NULL;
+	GtkTextBuffer *buffer = NULL;
 	gchar **activated = NULL;
 
+	ag = talkatu_action_group_new(TALKATU_FORMAT_HTML);
+	buffer = talkatu_buffer_new(ag);
+	talkatu_action_group_set_buffer(TALKATU_ACTION_GROUP(ag), buffer);
+
 	talkatu_action_group_activate_format(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_BOLD);
 	talkatu_action_group_activate_format(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_ITALIC);
 
@@ -58,10 +66,14 @@
 
 static void
 talkatu_test_action_group_activate_complex(void) {
-	GtkTextBuffer *buffer = talkatu_whole_buffer_new();
-	GSimpleActionGroup *ag = talkatu_buffer_get_action_group(TALKATU_BUFFER(buffer));
+	GSimpleActionGroup *ag = NULL;
+	GtkTextBuffer *buffer = NULL;
 	gchar **activated = NULL;
 
+	ag = talkatu_action_group_new(TALKATU_FORMAT_HTML);
+	buffer = talkatu_buffer_new(ag);
+	talkatu_action_group_set_buffer(TALKATU_ACTION_GROUP(ag), buffer);
+
 	talkatu_action_group_activate_format(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_BOLD);
 	talkatu_action_group_activate_format(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_ITALIC);
 	talkatu_action_group_activate_format(TALKATU_ACTION_GROUP(ag), TALKATU_ACTION_FORMAT_BOLD);
diff --git a/talkatu/tests/talkatutesthtmlserialization.c b/talkatu/tests/talkatutesthtmlserialization.c
--- a/talkatu/tests/talkatutesthtmlserialization.c
+++ b/talkatu/tests/talkatutesthtmlserialization.c
@@ -42,10 +42,15 @@
 
 static void
 talkatu_test_html_serialization(gconstpointer data) {
-	GtkTextBuffer *buffer = talkatu_html_buffer_new();
+	GtkTextBuffer *buffer = NULL;
+	GSimpleActionGroup *ag = NULL;
 	const gchar *html = (const gchar *)data;
 	gchar *actual = NULL;
 
+	ag = talkatu_action_group_new(TALKATU_FORMAT_HTML);
+	buffer = talkatu_buffer_new(ag);
+	talkatu_action_group_set_buffer(TALKATU_ACTION_GROUP(ag), buffer);
+
 	talkatu_markup_set_html(TALKATU_BUFFER(buffer), html, -1);
 	actual = talkatu_markup_get_html(buffer, NULL);
 
@@ -57,10 +62,15 @@
 static void
 talkatu_test_html_serialization_range(gconstpointer data) {
 	TalkatuTestHtmlSerializeData *d = (TalkatuTestHtmlSerializeData *)data;
-	GtkTextBuffer *buffer = talkatu_html_buffer_new();
+	GtkTextBuffer *buffer = NULL;
 	GtkTextIter start, end;
+	GSimpleActionGroup *ag = NULL;
 	gchar *actual = NULL;
 
+	ag = talkatu_action_group_new(TALKATU_FORMAT_HTML);
+	buffer = talkatu_buffer_new(ag);
+	talkatu_action_group_set_buffer(TALKATU_ACTION_GROUP(ag), buffer);
+
 	talkatu_markup_set_html(TALKATU_BUFFER(buffer), d->initial, -1);
 
 	gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(buffer), &start, d->start_offset);
