Codeberg

summaryrefslogtreecommitdiff
path: root/insert_recursive_snippet.c
diff options
context:
space:
mode:
Diffstat (limited to 'insert_recursive_snippet.c')
-rw-r--r--insert_recursive_snippet.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/insert_recursive_snippet.c b/insert_recursive_snippet.c
new file mode 100644
index 0000000..8c16651
--- /dev/null
+++ b/insert_recursive_snippet.c
@@ -0,0 +1,160 @@
+
+static void insert_recursive(GtkTextBuffer *buffer, GtkTextIter *iter, const char *text, GSList *tags) {
+ if (!text || !*text) return;
+
+ const char *p = text;
+ while (*p) {
+ // Strikethrough ~~
+ if (strncmp(p, "~~", 2) == 0) {
+ const char *end = strstr(p + 2, "~~");
+ if (end) {
+ char *inner = g_strndup(p + 2, end - p - 2);
+ GtkTextTag *tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "strikethrough");
+ GSList *new_tags = g_slist_prepend(g_slist_copy(tags), tag);
+ insert_recursive(buffer, iter, inner, new_tags);
+ g_slist_free(new_tags);
+ g_free(inner);
+ p = end + 2; continue;
+ }
+ }
+ // Bold+Italic ***
+ if (strncmp(p, "***", 3) == 0) {
+ const char *end = strstr(p + 3, "***");
+ if (end) {
+ char *inner = g_strndup(p + 3, end - p - 3);
+ GtkTextTag *t1 = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "bold");
+ GtkTextTag *t2 = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "italic");
+ GSList *new_tags = g_slist_prepend(g_slist_prepend(g_slist_copy(tags), t1), t2);
+ insert_recursive(buffer, iter, inner, new_tags);
+ g_slist_free(new_tags);
+ g_free(inner);
+ p = end + 3; continue;
+ }
+ }
+ // Bold ** or __
+ if (strncmp(p, "**", 2) == 0 || strncmp(p, "__", 2) == 0) {
+ const char *marker = strncmp(p, "**", 2) == 0 ? "**" : "__";
+ const char *end = strstr(p + 2, marker);
+ if (end) {
+ char *inner = g_strndup(p + 2, end - p - 2);
+ GtkTextTag *tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "bold");
+ GSList *new_tags = g_slist_prepend(g_slist_copy(tags), tag);
+ insert_recursive(buffer, iter, inner, new_tags);
+ g_slist_free(new_tags);
+ g_free(inner);
+ p = end + 2; continue;
+ }
+ }
+ // Italic * or _
+ if (*p == '*' || *p == '_') {
+ char marker[2] = {*p, 0};
+ const char *end = strpbrk(p + 1, marker);
+ if (end && *end == *p) {
+ char *inner = g_strndup(p + 1, end - p - 1);
+ GtkTextTag *tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "italic");
+ GSList *new_tags = g_slist_prepend(g_slist_copy(tags), tag);
+ insert_recursive(buffer, iter, inner, new_tags);
+ g_slist_free(new_tags);
+ g_free(inner);
+ p = end + 1; continue;
+ }
+ }
+ // Code `
+ if (*p == '`') {
+ const char *end = strchr(p + 1, '`');
+ if (end) {
+ char *inner = g_strndup(p + 1, end - p - 1);
+ GtkTextTag *tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "code");
+ GSList *new_tags = g_slist_prepend(g_slist_copy(tags), tag);
+ // Code is not recursive
+ GtkTextIter start_ins = *iter;
+ gtk_text_buffer_insert(buffer, iter, inner, -1);
+ for (GSList *l = new_tags; l; l = l->next) {
+ gtk_text_buffer_apply_tag(buffer, (GtkTextTag*)l->data, &start_ins, iter);
+ }
+ g_slist_free(new_tags);
+ g_free(inner);
+ p = end + 1; continue;
+ }
+ }
+ // Image ![alt](url)
+ if (strncmp(p, "![", 2) == 0) {
+ const char *alt_end = strchr(p + 2, ']');
+ if (alt_end && alt_end[1] == '(') {
+ const char *url_end = strchr(alt_end + 2, ')');
+ if (url_end) {
+ char *path_start = (char*)alt_end + 2;
+ char *path = g_strndup(path_start, url_end - path_start);
+ if (strncmp(path, "http", 4) == 0) {
+ // Placeholder for remote
+ char *msg = g_strdup_printf("[Remote Image: %s]", path);
+ GtkTextIter start_ins = *iter;
+ gtk_text_buffer_insert(buffer, iter, msg, -1);
+ g_free(msg);
+ } else {
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(path, 600, -1, TRUE, NULL);
+ if (pixbuf) {
+ gtk_text_buffer_insert_pixbuf(buffer, iter, pixbuf);
+ g_object_unref(pixbuf);
+ } else {
+ char *msg = g_strdup_printf("[Image not found: %s]", path);
+ gtk_text_buffer_insert(buffer, iter, msg, -1);
+ g_free(msg);
+ }
+ }
+ g_free(path);
+ p = url_end + 1; continue;
+ }
+ }
+ }
+ // Link [text](url)
+ if (*p == '[') {
+ const char *txt_end = strchr(p + 1, ']');
+ if (txt_end && txt_end[1] == '(') {
+ const char *url_end = strchr(txt_end + 2, ')');
+ if (url_end) {
+ char *txt = g_strndup(p + 1, txt_end - p - 1);
+ char *url = g_strndup(txt_end + 2, url_end - txt_end - 2);
+
+ GtkTextTag *url_tag = gtk_text_buffer_create_tag(buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL);
+ g_object_set_data_full(G_OBJECT(url_tag), "url", g_strdup(url), g_free);
+
+ GSList *new_tags = g_slist_prepend(g_slist_copy(tags), url_tag);
+ insert_recursive(buffer, iter, txt, new_tags);
+
+ g_slist_free(new_tags);
+ g_free(txt); g_free(url);
+ p = url_end + 1; continue;
+ }
+ }
+ }
+ // Auto-link http://...
+ if (strncmp(p, "http://", 7) == 0 || strncmp(p, "https://", 8) == 0) {
+ const char *end = p;
+ while (*end && !isspace(*end) && *end != ')' && *end != ']' && *end != '>') end++;
+ char *url = g_strndup(p, end - p);
+
+ GtkTextTag *url_tag = gtk_text_buffer_create_tag(buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL);
+ g_object_set_data_full(G_OBJECT(url_tag), "url", g_strdup(url), g_free);
+
+ GtkTextIter start_ins = *iter;
+ gtk_text_buffer_insert(buffer, iter, url, -1);
+
+ // Apply background tags + url tag
+ for (GSList *l = tags; l; l = l->next) gtk_text_buffer_apply_tag(buffer, (GtkTextTag*)l->data, &start_ins, iter);
+ gtk_text_buffer_apply_tag(buffer, url_tag, &start_ins, iter);
+
+ g_free(url);
+ p = end; continue;
+ }
+
+ // Plain text
+ GtkTextIter start_ins = *iter;
+ char buf[2] = {*p, 0};
+ gtk_text_buffer_insert(buffer, iter, buf, 1);
+ for (GSList *l = tags; l; l = l->next) {
+ gtk_text_buffer_apply_tag(buffer, (GtkTextTag*)l->data, &start_ins, iter);
+ }
+ p++;
+ }
+}