diff options
Diffstat (limited to 'hardinfo2/help-viewer')
| -rw-r--r-- | hardinfo2/help-viewer/egg-markdown.c | 1586 | ||||
| -rw-r--r-- | hardinfo2/help-viewer/help-viewer.c | 514 | ||||
| -rw-r--r-- | hardinfo2/help-viewer/markdown-text-view.c | 637 | 
3 files changed, 0 insertions, 2737 deletions
diff --git a/hardinfo2/help-viewer/egg-markdown.c b/hardinfo2/help-viewer/egg-markdown.c deleted file mode 100644 index 4056d4f9..00000000 --- a/hardinfo2/help-viewer/egg-markdown.c +++ /dev/null @@ -1,1586 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> - * Copyright (C) 2009 Leandro Pereira <leandro@hardinfo.org> - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#define _GNU_SOURCE -#include <stdio.h> -#include <string.h> -#include <glib.h> - -#include "egg-markdown.h" - -/******************************************************************************* - * - * This is a simple Markdown parser. - * It can output to Pango, HTML or plain text. The following limitations are - * already known, and properly deliberate: - * - * - No code section support - * - No ordered list support - * - No blockquote section support - * - No image support - * - No links or email support - * - No backslash escapes support - * - No HTML escaping support - * - Auto-escapes certain word patterns, like http:// - * - * It does support the rest of the standard pretty well, although it's not - * been run against any conformance tests. The parsing is single pass, with - * a simple enumerated intepretor mode and a single line back-memory. - * - ******************************************************************************/ - -static void     egg_markdown_finalize	(GObject		*object); - -#define EGG_MARKDOWN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_MARKDOWN, EggMarkdownPrivate)) - -typedef gchar *(EggMarkdownLinkBuilder)(gchar *title, gchar *uri, gint link_id); -typedef gchar *(EggMarkdownImageBuilder)(gchar *alt_text, gchar *path, gint link_id); - -typedef enum { -	EGG_MARKDOWN_MODE_BLANK, -	EGG_MARKDOWN_MODE_RULE, -	EGG_MARKDOWN_MODE_BULLETT, -	EGG_MARKDOWN_MODE_PARA, -	EGG_MARKDOWN_MODE_H1, -	EGG_MARKDOWN_MODE_H2, -	EGG_MARKDOWN_MODE_UNKNOWN -} EggMarkdownMode; - -typedef struct { -	const gchar *em_start; -	const gchar *em_end; -	const gchar *strong_start; -	const gchar *strong_end; -	const gchar *code_start; -	const gchar *code_end; -	const gchar *h1_start; -	const gchar *h1_end; -	const gchar *h2_start; -	const gchar *h2_end; -	const gchar *bullett_start; -	const gchar *bullett_end; -	const gchar *rule; -	 -	EggMarkdownLinkBuilder *link_builder; -	EggMarkdownImageBuilder *image_builder; -} EggMarkdownTags; - -struct EggMarkdownPrivate -{ -	EggMarkdownMode		 mode; -	EggMarkdownTags		 tags; -	EggMarkdownOutput	 output; -	gint			 max_lines; -	guint			 line_count; -	gboolean		 smart_quoting; -	gboolean		 escape; -	gboolean		 autocode; -	GString			*pending; -	GString			*processed; -	GArray			*link_table; -}; - -G_DEFINE_TYPE (EggMarkdown, egg_markdown, G_TYPE_OBJECT) - -/** - * egg_markdown_to_text_line_is_rule: - * - * Horizontal rules are created by placing three or more hyphens, asterisks, - * or underscores on a line by themselves. - * You may use spaces between the hyphens or asterisks. - **/ -static gboolean -egg_markdown_to_text_line_is_rule (const gchar *line) -{ -	guint i; -	guint len; -	guint count = 0; -	gchar *copy = NULL; -	gboolean ret = FALSE; - -	len = strnlen (line, EGG_MARKDOWN_MAX_LINE_LENGTH); -	if (len == 0) -		goto out; - -	/* replace non-rule chars with ~ */ -	copy = g_strdup (line); -	g_strcanon (copy, "-*_ ", '~'); -	for (i=0; i<len; i++) { -		if (copy[i] == '~') -			goto out; -		if (copy[i] != ' ') -			count++; -	} - -	/* if we matched, return true */ -	if (count >= 3) -		ret = TRUE; -out: -	g_free (copy); -	return ret; -} - -/** - * egg_markdown_to_text_line_is_bullett: - **/ -static gboolean -egg_markdown_to_text_line_is_bullett (const gchar *line) -{ -	return (g_str_has_prefix (line, "- ") || -		g_str_has_prefix (line, "* ") || -		g_str_has_prefix (line, "+ ") || -		g_str_has_prefix (line, " - ") || -		g_str_has_prefix (line, " * ") || -		g_str_has_prefix (line, " + ")); -} - -/** - * egg_markdown_to_text_line_is_header1: - **/ -static gboolean -egg_markdown_to_text_line_is_header1 (const gchar *line) -{ -	return g_str_has_prefix (line, "# "); -} - -/** - * egg_markdown_to_text_line_is_header2: - **/ -static gboolean -egg_markdown_to_text_line_is_header2 (const gchar *line) -{ -	return g_str_has_prefix (line, "## "); -} - -/** - * egg_markdown_to_text_line_is_header1_type2: - **/ -static gboolean -egg_markdown_to_text_line_is_header1_type2 (const gchar *line) -{ -	return g_str_has_prefix (line, "==="); -} - -/** - * egg_markdown_to_text_line_is_header2_type2: - **/ -static gboolean -egg_markdown_to_text_line_is_header2_type2 (const gchar *line) -{ -	return g_str_has_prefix (line, "---"); -} - -#if 0 -/** - * egg_markdown_to_text_line_is_code: - **/ -static gboolean -egg_markdown_to_text_line_is_code (const gchar *line) -{ -	return (g_str_has_prefix (line, "    ") || g_str_has_prefix (line, "\t")); -} - -/** - * egg_markdown_to_text_line_is_blockquote: - **/ -static gboolean -egg_markdown_to_text_line_is_blockquote (const gchar *line) -{ -	return (g_str_has_prefix (line, "> ")); -} -#endif - -/** - * egg_markdown_to_text_line_is_blank: - **/ -static gboolean -egg_markdown_to_text_line_is_blank (const gchar *line) -{ -	guint i; -	guint len; -	gboolean ret = FALSE; - -	len = strnlen (line, EGG_MARKDOWN_MAX_LINE_LENGTH); - -	/* a line with no characters is blank by definition */ -	if (len == 0) { -		ret = TRUE; -		goto out; -	} - -	/* find if there are only space chars */ -	for (i=0; i<len; i++) { -		if (line[i] != ' ' && line[i] != '\t') -			goto out; -	} - -	/* if we matched, return true */ -	ret = TRUE; -out: -	return ret; -} - -/** - * egg_markdown_replace: - **/ -static gchar * -egg_markdown_replace (const gchar *haystack, const gchar *needle, const gchar *replace) -{ -	gchar *new; -	gchar **split; - -	split = g_strsplit (haystack, needle, -1); -	new = g_strjoinv (replace, split); -	g_strfreev (split); - -	return new; -} - -/** - * egg_markdown_strstr_spaces: - **/ -static gchar * -egg_markdown_strstr_spaces (const gchar *haystack, const gchar *needle) -{ -	gchar *found; -	const gchar *haystack_new = haystack; - -retry: -	/* don't find if surrounded by spaces */ -	found = strstr (haystack_new, needle); -	if (found == NULL) -		return NULL; - -	/* start of the string, always valid */ -	if (found == haystack) -		return found; - -	/* end of the string, always valid */ -	if (*(found-1) == ' ' && *(found+1) == ' ') { -		haystack_new = found+1; -		goto retry; -	} -	return found; -} - - -/** - * egg_markdown_to_text_line_formatter: - **/ -static gchar * -egg_markdown_to_text_line_formatter (const gchar *line, const gchar *formatter, const gchar *left, const gchar *right) -{ -	guint len; -	gchar *str1; -	gchar *str2; -	gchar *start = NULL; -	gchar *middle = NULL; -	gchar *end = NULL; -	gchar *copy = NULL; -	gchar *data = NULL; -	gchar *temp; - -	/* needed to know for shifts */ -	len = strnlen (formatter, EGG_MARKDOWN_MAX_LINE_LENGTH); -	if (len == 0) -		goto out; - -	/* find sections */ -	copy = g_strdup (line); -	str1 = egg_markdown_strstr_spaces (copy, formatter); -	if (str1 != NULL) { -		*str1 = '\0'; -		str2 = egg_markdown_strstr_spaces (str1+len, formatter); -		if (str2 != NULL) { -			*str2 = '\0'; -			middle = str1 + len; -			start = copy; -			end = str2 + len; -		} -	} -	 -	/* if we found, replace and keep looking for the same string */ -	if (start != NULL && middle != NULL && end != NULL) { -                temp = g_strdup_printf ("%s%s%s%s%s", start, left, middle, right, end); -		/* recursive */ -		data = egg_markdown_to_text_line_formatter (temp, formatter, left, right); -		g_free (temp); -	} else { -		/* not found, keep return as-is */ -		data = g_strdup (line); -	} -out: -	g_free (copy); -	return data; -} - -static gchar * -egg_markdown_to_text_line_formatter_image (EggMarkdown *self, const gchar *line) -{ -	const guint len = 2;	/* needed to know for shifts */ -	gchar *str1; -	gchar *str2; -	gchar *start = NULL; -	gchar *path = NULL; -	gchar *alt_text = NULL; -	gchar *end = NULL; -	gchar *copy = NULL; -	gchar *data = NULL; - -	/* find sections */ -	copy = g_strdup (line); -	str1 = egg_markdown_strstr_spaces (copy, "!["); -	if (str1 != NULL) { -		*str1 = '\0'; -		str2 = egg_markdown_strstr_spaces (str1+len, "]"); -		if (str2 != NULL) { -			*str2 = '\0'; -			start = copy; -			alt_text = str1 + len; -			 -                        str2 = strstr (str2 + 1, "("); -			if (str2 != NULL) { -                           *str2 = '\0'; -                            -                           str1 = strstr (str2 + 1, ")"); -                           if (str1 != NULL) { -                             *str1 = '\0'; -                             path = str2 + 1; -                             end = str1 + 1; -                           } -			} -		} -	} -	 -	/* if we found, replace and keep looking for the same string */ -	if (start && (path && *path) && alt_text && end) { -	        gchar *formatted_img; -	        gchar *path_copy = g_strdup(path); -	         -	        g_array_append_val(self->priv->link_table, path_copy); -	         -	        formatted_img = self->priv->tags.image_builder(alt_text, -                                                               path, -                                                               self->priv->link_table->len - 1); -	         -                data = g_strdup_printf ("%s%s%s", -                                        start, formatted_img, end); -                 -                g_free(formatted_img); -	} else { -		/* not found, keep return as-is */ -		data = g_strdup (line); -	} - -	g_free (copy); -	return data; -} - - -/** - * egg_markdown_to_text_line_formatter_link: - **/ -static gchar * -egg_markdown_to_text_line_formatter_link (EggMarkdown *self, const gchar *line) -{ -	const guint len = 1;	/* needed to know for shifts */ -	gchar *str1; -	gchar *str2; -	gchar *start = NULL; -	gchar *link = NULL; -	gchar *link_title = NULL; -	gchar *end = NULL; -	gchar *copy = NULL; -	gchar *data = NULL; - -	/* find sections */ -	copy = g_strdup (line); -	str1 = egg_markdown_strstr_spaces (copy, "["); -	if (str1 != NULL) { -		*str1 = '\0'; -		str2 = egg_markdown_strstr_spaces (str1+len, "]"); -		if (str2 != NULL) { -			*str2 = '\0'; -			start = copy; -			link = str1 + len; -			end = str2 + len; -			 -                        str2 = strstr (link, " "); -			if (str2 != NULL) { -                           *str2 = '\0'; -                           link_title = str2 + len; -			} -		} -	} -	 -	/* if we found, replace and keep looking for the same string */ -	if (start && (link && *link) && link_title && end) { -	        gchar *formatted_link; -	        gchar *link_copy = g_strdup(link); -	         -	        g_array_append_val(self->priv->link_table, link_copy); -	         -	        formatted_link = self->priv->tags.link_builder(link_title, -	                                                       link, -	                                                       self->priv->link_table->len - 1); -                      -                data = g_strdup_printf ("%s%s%s", -                                        start, formatted_link, end); -                 -                g_free(formatted_link); -	} else { -		/* not found, keep return as-is */ -		data = g_strdup (line); -	} - -	g_free (copy); -	return data; -} - -void -egg_markdown_clear(EggMarkdown *self) -{ -        int i; -         -        for (i = 0; i < self->priv->link_table->len; i++) { -             g_free(g_array_index(self->priv->link_table, gchar *, i)); -        } - -        g_array_free(self->priv->link_table, TRUE); -	self->priv->link_table = g_array_new(FALSE, FALSE, sizeof(gchar *)); -} - -gchar * -egg_markdown_get_link_uri(EggMarkdown *self, const gint link_id) -{ -        g_return_val_if_fail(link_id < self->priv->link_table->len, NULL); - -        return g_strdup(g_array_index(self->priv->link_table, gchar *, link_id)); -} - -/** - * egg_markdown_to_text_line_format_sections: - **/ -static gchar * -egg_markdown_to_text_line_format_sections (EggMarkdown *self, const gchar *line) -{ -	gchar *data = g_strdup (line); -	gchar *temp; - -	/* smart quoting */ -	if (self->priv->smart_quoting) { -	        if (self->priv->escape) { -                     temp = data; -                     data = egg_markdown_to_text_line_formatter (temp, """, "“", "”"); -                     g_free (temp); - -                     temp = data; -                     data = egg_markdown_to_text_line_formatter (temp, "'", "‘", "’"); -                     g_free (temp); -                } else { -                     temp = data; -                     data = egg_markdown_to_text_line_formatter (temp, "\"", "“", "”"); -                     g_free (temp); - -                     temp = data; -                     data = egg_markdown_to_text_line_formatter (temp, "'", "‘", "’"); -                     g_free (temp); -                } -	} - -	/* image */ -	temp = data; -	data = egg_markdown_to_text_line_formatter_image (self, temp); -	g_free(temp); - -	/* link */ -	temp = data; -	data = egg_markdown_to_text_line_formatter_link (self, temp); -	g_free(temp); - -	/* bold1 */ -	temp = data; -	data = egg_markdown_to_text_line_formatter (temp, "**", self->priv->tags.strong_start, self->priv->tags.strong_end); -	g_free (temp); - -	/* bold2 */ -	temp = data; -	data = egg_markdown_to_text_line_formatter (temp, "__", self->priv->tags.strong_start, self->priv->tags.strong_end); -	g_free (temp); - -	/* italic1 */ -	temp = data; -	data = egg_markdown_to_text_line_formatter (temp, "*", self->priv->tags.em_start, self->priv->tags.em_end); -	g_free (temp); - -	/* italic2 */ -	temp = data; -	data = egg_markdown_to_text_line_formatter (temp, "_", self->priv->tags.em_start, self->priv->tags.em_end); -	g_free (temp); -	 -	/* em-dash */ -	temp = data; -	data = egg_markdown_replace (temp, " -- ", " — "); -	g_free (temp); - -	return data; -} - -/** - * egg_markdown_to_text_line_format: - **/ -static gchar * -egg_markdown_to_text_line_format (EggMarkdown *self, const gchar *line) -{ -	guint i; -	gchar *text; -	gboolean mode = FALSE; -	gchar **codes; -	GString *string; - -	/* optimise the trivial case where we don't have any code tags */ -	text = strstr (line, "`"); -	if (text == NULL) { -		text = egg_markdown_to_text_line_format_sections (self, line); -		goto out; -	} - -	/* we want to parse the code sections without formatting */ -	codes = g_strsplit (line, "`", -1); -	string = g_string_new (""); -	for (i=0; codes[i] != NULL; i++) { -		if (!mode) { -			text = egg_markdown_to_text_line_format_sections (self, codes[i]); -			g_string_append (string, text); -			g_free (text); -			mode = TRUE; -		} else { -			/* just append without formatting */ -			g_string_append (string, self->priv->tags.code_start); -			g_string_append (string, codes[i]); -			g_string_append (string, self->priv->tags.code_end); -			mode = FALSE; -		} -	} -	text = g_string_free (string, FALSE); -out: -	return text; -} - -/** - * egg_markdown_add_pending: - **/ -static gboolean -egg_markdown_add_pending (EggMarkdown *self, const gchar *line) -{ -	gchar *copy; - -	/* would put us over the limit */ -	if (self->priv->line_count >= self->priv->max_lines) -		return FALSE; - -	copy = g_strdup (line); - -	/* strip leading and trailing spaces */ -	g_strstrip (copy); - -	/* append */ -	g_string_append_printf (self->priv->pending, "%s ", copy); - -	g_free (copy); -	return TRUE; -} - -/** - * egg_markdown_add_pending_header: - **/ -static gboolean -egg_markdown_add_pending_header (EggMarkdown *self, const gchar *line) -{ -	gchar *copy; -	gboolean ret; - -	/* strip trailing # */ -	copy = g_strdup (line); -	g_strdelimit (copy, "#", ' '); -	ret = egg_markdown_add_pending (self, copy); -	g_free (copy); -	return ret; -} - -/** - * egg_markdown_count_chars_in_word: - **/ -static guint -egg_markdown_count_chars_in_word (const gchar *text, gchar find) -{ -	guint i; -	guint len; -	guint count = 0; - -	/* get length */ -	len = strnlen (text, EGG_MARKDOWN_MAX_LINE_LENGTH); -	if (len == 0) -		goto out; - -	/* find matching chars */ -	for (i=0; i<len; i++) { -		if (text[i] == find) -			count++; -	} -out: -	return count; -} - -/** - * egg_markdown_word_is_code: - **/ -static gboolean -egg_markdown_word_is_code (const gchar *text) -{ -	/* already code */ -	if (g_str_has_prefix (text, "`")) -		return FALSE; -	if (g_str_has_suffix (text, "`")) -		return FALSE; - -	/* paths */ -	if (g_str_has_prefix (text, "/")) -		return TRUE; - -	/* bugzillas */ -	if (g_str_has_prefix (text, "#")) -		return TRUE; - -	/* uri's */ -	if (g_str_has_prefix (text, "http://")) -		return TRUE; -	if (g_str_has_prefix (text, "https://")) -		return TRUE; -	if (g_str_has_prefix (text, "ftp://")) -		return TRUE; - -	/* patch files */ -	if (g_strrstr (text, ".patch") != NULL) -		return TRUE; -	if (g_strrstr (text, ".diff") != NULL) -		return TRUE; - -	/* function names */ -	if (g_strrstr (text, "()") != NULL) -		return TRUE; - -	/* email addresses */ -	if (g_strrstr (text, "@") != NULL) -		return TRUE; - -	/* compiler defines */ -	if (text[0] != '_' && -	    egg_markdown_count_chars_in_word (text, '_') > 1) -		return TRUE; - -	/* nothing special */ -	return FALSE; -} - -/** - * egg_markdown_word_auto_format_code: - **/ -static gchar * -egg_markdown_word_auto_format_code (const gchar *text) -{ -	guint i; -	gchar *temp; -	gchar **words; -	gboolean ret = FALSE; - -	/* split sentence up with space */ -	words = g_strsplit (text, " ", -1); - -	/* search each word */ -	for (i=0; words[i] != NULL; i++) { -		if (egg_markdown_word_is_code (words[i])) { -			temp = g_strdup_printf ("`%s`", words[i]); -			g_free (words[i]); -			words[i] = temp; -			ret = TRUE; -		} -	} - -	/* no replacements, so just return a copy */ -	if (!ret) { -		temp = g_strdup (text); -		goto out; -	} - -	/* join the array back into a string */ -	temp = g_strjoinv (" ", words); -out: -	g_strfreev (words); -	return temp; -} - -/** - * egg_markdown_flush_pending: - **/ -static void -egg_markdown_flush_pending (EggMarkdown *self) -{ -	gchar *copy; -	gchar *temp; - -	/* no data yet */ -	if (self->priv->mode == EGG_MARKDOWN_MODE_UNKNOWN) -		return; - -	/* remove trailing spaces */ -	while (g_str_has_suffix (self->priv->pending->str, " ")) -		g_string_set_size (self->priv->pending, self->priv->pending->len - 1); - -	/* pango requires escaping */ -	copy = g_strdup (self->priv->pending->str); -	if (!self->priv->escape && self->priv->output == EGG_MARKDOWN_OUTPUT_PANGO) { -		g_strdelimit (copy, "<", '('); -		g_strdelimit (copy, ">", ')'); -	} - -	/* check words for code */ -	if (self->priv->autocode && -	    (self->priv->mode == EGG_MARKDOWN_MODE_PARA || -	     self->priv->mode == EGG_MARKDOWN_MODE_BULLETT)) { -		temp = egg_markdown_word_auto_format_code (copy); -		g_free (copy); -		copy = temp; -	} - -	/* escape */ -	if (self->priv->escape) { -		temp = g_markup_escape_text (copy, -1); -		g_free (copy); -		copy = temp; -	} - -	/* do formatting */ -	temp = egg_markdown_to_text_line_format (self, copy); -	if (self->priv->mode == EGG_MARKDOWN_MODE_BULLETT) { -		g_string_append_printf (self->priv->processed, "%s%s%s\n", self->priv->tags.bullett_start, temp, self->priv->tags.bullett_end); -		self->priv->line_count++; -	} else if (self->priv->mode == EGG_MARKDOWN_MODE_H1) { -		g_string_append_printf (self->priv->processed, "%s%s%s\n", self->priv->tags.h1_start, temp, self->priv->tags.h1_end); -	} else if (self->priv->mode == EGG_MARKDOWN_MODE_H2) { -		g_string_append_printf (self->priv->processed, "%s%s%s\n", self->priv->tags.h2_start, temp, self->priv->tags.h2_end); -	} else if (self->priv->mode == EGG_MARKDOWN_MODE_PARA || -		   self->priv->mode == EGG_MARKDOWN_MODE_RULE) { -		g_string_append_printf (self->priv->processed, "%s\n", temp); -		self->priv->line_count++; -	} - -	DEBUG ("adding '%s'", temp); - -	/* clear */ -	g_string_truncate (self->priv->pending, 0); -	g_free (copy); -	g_free (temp); -} - -/** - * egg_markdown_to_text_line_process: - **/ -static gboolean -egg_markdown_to_text_line_process (EggMarkdown *self, const gchar *line) -{ -	gboolean ret; - -	/* blank */ -	ret = egg_markdown_to_text_line_is_blank (line); -	if (ret) { -		DEBUG ("blank: '%s'", line); -		egg_markdown_flush_pending (self); -		/* a new line after a list is the end of list, not a gap */ -		if (self->priv->mode != EGG_MARKDOWN_MODE_BULLETT) -			ret = egg_markdown_add_pending (self, "\n"); -		self->priv->mode = EGG_MARKDOWN_MODE_BLANK; -		goto out; -	} - -	/* header1_type2 */ -	ret = egg_markdown_to_text_line_is_header1_type2 (line); -	if (ret) { -		DEBUG ("header1_type2: '%s'", line); -		if (self->priv->mode == EGG_MARKDOWN_MODE_PARA) -			self->priv->mode = EGG_MARKDOWN_MODE_H1; -		goto out; -	} - -	/* header2_type2 */ -	ret = egg_markdown_to_text_line_is_header2_type2 (line); -	if (ret) { -		DEBUG ("header2_type2: '%s'", line); -		if (self->priv->mode == EGG_MARKDOWN_MODE_PARA) -			self->priv->mode = EGG_MARKDOWN_MODE_H2; -		goto out; -	} - -	/* rule */ -	ret = egg_markdown_to_text_line_is_rule (line); -	if (ret) { -		DEBUG ("rule: '%s'", line); -		egg_markdown_flush_pending (self); -		self->priv->mode = EGG_MARKDOWN_MODE_RULE; -		ret = egg_markdown_add_pending (self, self->priv->tags.rule); -		goto out; -	} - -	/* bullett */ -	ret = egg_markdown_to_text_line_is_bullett (line); -	if (ret) { -		DEBUG ("bullett: '%s'", line); -		egg_markdown_flush_pending (self); -		self->priv->mode = EGG_MARKDOWN_MODE_BULLETT; -		ret = egg_markdown_add_pending (self, &line[2]); -		goto out; -	} - -	/* header1 */ -	ret = egg_markdown_to_text_line_is_header1 (line); -	if (ret) { -		DEBUG ("header1: '%s'", line); -		egg_markdown_flush_pending (self); -		self->priv->mode = EGG_MARKDOWN_MODE_H1; -		ret = egg_markdown_add_pending_header (self, &line[2]); -		goto out; -	} - -	/* header2 */ -	ret = egg_markdown_to_text_line_is_header2 (line); -	if (ret) { -		DEBUG ("header2: '%s'", line); -		egg_markdown_flush_pending (self); -		self->priv->mode = EGG_MARKDOWN_MODE_H2; -		ret = egg_markdown_add_pending_header (self, &line[3]); -		goto out; -	} - -	/* paragraph */ -	if (self->priv->mode == EGG_MARKDOWN_MODE_BLANK || self->priv->mode == EGG_MARKDOWN_MODE_UNKNOWN) { -		egg_markdown_flush_pending (self); -		self->priv->mode = EGG_MARKDOWN_MODE_PARA; -	} - -	/* add to pending */ -	DEBUG ("continue: '%s'", line); -	ret = egg_markdown_add_pending (self, line); -out: -	/* if we failed to add, we don't know the mode */ -	if (!ret) -		self->priv->mode = EGG_MARKDOWN_MODE_UNKNOWN; -	return ret; -} - -/** - * egg_markdown_linkbuilder_pango: - **/ -static gchar * -egg_markdown_linkbuilder_pango (gchar *title, gchar *uri, gint link_id) -{ -       /* FIXME: This is a nasty hack, since extending Pango markup to allow new tags -        *        is too complicated. We use the language code as a link index -        *        since it won't allow anything besides letters or numbers. -        *        To obtain the link URI, use egg_markdown_get_link_uri(). */ -       return g_strdup_printf("<span lang=\"%d\" foreground=\"blue\"><u>%s</u></span>", -                              link_id, title); -} - -/** - * egg_markdown_linkbuilder_html - **/ -static gchar * -egg_markdown_linkbuilder_html (gchar *title, gchar *uri, gint link_id) -{ -        return g_strdup_printf("<a href=\"%s\">%s</a>", uri, title); -} - -/** - * egg_markdown_linkbuilder_text - **/ -static gchar * -egg_markdown_linkbuilder_text (gchar *title, gchar *uri, gint link_id) -{ -        return g_strdup_printf("%s (%s)", title, uri); -} - -/** - * egg_markdown_imagebuilder_pango: - **/ -static gchar * -egg_markdown_imagebuilder_pango (gchar *alt_text, gchar *uri, gint link_id) -{ -       /* FIXME See egg_markdown_linkbuilder_pango() */ -       return g_strdup_printf("<span lang=\"%d\" underline=\"double\">%s</span>", -                              link_id, alt_text); -} - -/** - * egg_markdown_imagebuilder_html - **/ -static gchar * -egg_markdown_imagebuilder_html (gchar *alt_text, gchar *uri, gint link_id) -{ -        return g_strdup_printf("<img src=\"%s\" alt=\"%s\">", uri, alt_text); -} - -/** - * egg_markdown_imagebuilder_text - **/ -static gchar * -egg_markdown_imagebuilder_text (gchar *alt_text, gchar *uri, gint link_id) -{ -        return g_strdup(alt_text); -} - -/** - * egg_markdown_set_output: - **/ -gboolean -egg_markdown_set_output (EggMarkdown *self, EggMarkdownOutput output) -{ -	gboolean ret = TRUE; -	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE); - -	/* PangoMarkup */ -	if (output == EGG_MARKDOWN_OUTPUT_PANGO) { -		self->priv->tags.em_start = "<i>"; -		self->priv->tags.em_end = "</i>"; -		self->priv->tags.strong_start = "<b>"; -		self->priv->tags.strong_end = "</b>"; -		self->priv->tags.code_start = "<tt><span bgcolor=\"#eee\">"; -		self->priv->tags.code_end = "</span></tt>"; -		self->priv->tags.h1_start = "<span color=\"#444\" size=\"xx-large\"><b>"; -		self->priv->tags.h1_end = "</b></span>"; -		self->priv->tags.h2_start = "<big><b>"; -		self->priv->tags.h2_end = "</b></big>"; -		self->priv->tags.bullett_start = "  • "; -		self->priv->tags.bullett_end = ""; -		self->priv->tags.rule = "⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯\n"; -		self->priv->tags.link_builder = egg_markdown_linkbuilder_pango; -		self->priv->tags.image_builder = egg_markdown_imagebuilder_pango; - -	/* XHTML */ -	} else if (output == EGG_MARKDOWN_OUTPUT_HTML) { -		self->priv->tags.em_start = "<em>"; -		self->priv->tags.em_end = "<em>"; -		self->priv->tags.strong_start = "<strong>"; -		self->priv->tags.strong_end = "</strong>"; -		self->priv->tags.code_start = "<code>"; -		self->priv->tags.code_end = "</code>"; -		self->priv->tags.h1_start = "<h1>"; -		self->priv->tags.h1_end = "</h1>"; -		self->priv->tags.h2_start = "<h2>"; -		self->priv->tags.h2_end = "</h2>"; -		self->priv->tags.bullett_start = "<li>"; -		self->priv->tags.bullett_end = "</li>"; -		self->priv->tags.rule = "<hr>"; -		self->priv->tags.link_builder = egg_markdown_linkbuilder_html; -		self->priv->tags.image_builder = egg_markdown_imagebuilder_html; - -	/* plain text */ -	} else if (output == EGG_MARKDOWN_OUTPUT_TEXT) { -		self->priv->tags.em_start = ""; -		self->priv->tags.em_end = ""; -		self->priv->tags.strong_start = ""; -		self->priv->tags.strong_end = ""; -		self->priv->tags.code_start = ""; -		self->priv->tags.code_end = ""; -		self->priv->tags.h1_start = "["; -		self->priv->tags.h1_end = "]"; -		self->priv->tags.h2_start = "-"; -		self->priv->tags.h2_end = "-"; -		self->priv->tags.bullett_start = "* "; -		self->priv->tags.bullett_end = ""; -		self->priv->tags.rule = " ----- \n"; -		self->priv->tags.link_builder = egg_markdown_linkbuilder_text; -		self->priv->tags.image_builder = egg_markdown_imagebuilder_text; - -	/* unknown */ -	} else { -		g_warning ("unknown output enum"); -		ret = FALSE; -	} - -	/* save if valid */ -	if (ret) -		self->priv->output = output; -	return ret; -} - -/** - * egg_markdown_set_max_lines: - **/ -gboolean -egg_markdown_set_max_lines (EggMarkdown *self, gint max_lines) -{ -	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE); -	self->priv->max_lines = max_lines; -	return TRUE; -} - -/** - * egg_markdown_set_smart_quoting: - **/ -gboolean -egg_markdown_set_smart_quoting (EggMarkdown *self, gboolean smart_quoting) -{ -	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE); -	self->priv->smart_quoting = smart_quoting; -	return TRUE; -} - -/** - * egg_markdown_set_escape: - **/ -gboolean -egg_markdown_set_escape (EggMarkdown *self, gboolean escape) -{ -	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE); -	self->priv->escape = escape; -	return TRUE; -} - -/** - * egg_markdown_set_autocode: - **/ -gboolean -egg_markdown_set_autocode (EggMarkdown *self, gboolean autocode) -{ -	g_return_val_if_fail (EGG_IS_MARKDOWN (self), FALSE); -	self->priv->autocode = autocode; -	return TRUE; -} - -/** - * egg_markdown_parse: - **/ -gchar * -egg_markdown_parse (EggMarkdown *self, const gchar *markdown) -{ -	gchar **lines; -	guint i; -	guint len; -	gchar *temp; -	gboolean ret; - -	g_return_val_if_fail (EGG_IS_MARKDOWN (self), NULL); -	g_return_val_if_fail (self->priv->output != EGG_MARKDOWN_OUTPUT_UNKNOWN, NULL); - -	DEBUG ("input='%s'", markdown); - -	/* process */ -	self->priv->mode = EGG_MARKDOWN_MODE_UNKNOWN; -	self->priv->line_count = 0; -	g_string_truncate (self->priv->pending, 0); -	g_string_truncate (self->priv->processed, 0); -	lines = g_strsplit (markdown, "\n", -1); -	len = g_strv_length (lines); - -	/* process each line */ -	for (i=0; i<len; i++) { -		ret = egg_markdown_to_text_line_process (self, lines[i]); -		if (!ret) -			break; -	} -	g_strfreev (lines); -	egg_markdown_flush_pending (self); - -	/* remove trailing \n */ -	while (g_str_has_suffix (self->priv->processed->str, "\n")) -		g_string_set_size (self->priv->processed, self->priv->processed->len - 1); - -	/* get a copy */ -	temp = g_strdup (self->priv->processed->str); -	g_string_truncate (self->priv->pending, 0); -	g_string_truncate (self->priv->processed, 0); - -	DEBUG ("output='%s'", temp); - -	return temp; -} - -/** - * egg_markdown_class_init: - * @klass: The EggMarkdownClass - **/ -static void -egg_markdown_class_init (EggMarkdownClass *klass) -{ -	GObjectClass *object_class = G_OBJECT_CLASS (klass); -	object_class->finalize = egg_markdown_finalize; -	g_type_class_add_private (klass, sizeof (EggMarkdownPrivate)); -} - -/** - * egg_markdown_init: - **/ -static void -egg_markdown_init (EggMarkdown *self) -{ -	self->priv = EGG_MARKDOWN_GET_PRIVATE (self); - -	self->priv->mode = EGG_MARKDOWN_MODE_UNKNOWN; -	self->priv->output = EGG_MARKDOWN_OUTPUT_UNKNOWN; -	self->priv->pending = g_string_new (""); -	self->priv->processed = g_string_new (""); -	self->priv->link_table = g_array_new(FALSE, FALSE, sizeof(gchar *)); -	self->priv->max_lines = -1; -	self->priv->smart_quoting = FALSE; -	self->priv->escape = FALSE; -	self->priv->autocode = FALSE; -} - -/** - * egg_markdown_finalize: - * @object: The object to finalize - **/ -static void -egg_markdown_finalize (GObject *object) -{ -	EggMarkdown *self; -        int i; - -	g_return_if_fail (EGG_IS_MARKDOWN (object)); - -	self = EGG_MARKDOWN (object); - -	g_return_if_fail (self->priv != NULL); -	g_string_free (self->priv->pending, TRUE); -	g_string_free (self->priv->processed, TRUE); -         -        for (i = 0; i < self->priv->link_table->len; i++) { -             g_free(g_array_index(self->priv->link_table, gchar *, i)); -        } -	g_array_free (self->priv->link_table, TRUE); - -	G_OBJECT_CLASS (egg_markdown_parent_class)->finalize (object); -} - -/** - * egg_markdown_new: - * - * Return value: a new EggMarkdown object. - **/ -EggMarkdown * -egg_markdown_new (void) -{ -	EggMarkdown *self; -	self = g_object_new (EGG_TYPE_MARKDOWN, NULL); -	return EGG_MARKDOWN (self); -} - -/*************************************************************************** - ***                          MAKE CHECK TESTS                           *** - ***************************************************************************/ -#ifdef EGG_TEST -#include "egg-test.h" - -void -egg_markdown_test (EggTest *test) -{ -	EggMarkdown *self; -	gchar *text; -	gboolean ret; -	const gchar *markdown; -	const gchar *markdown_expected; - -	if (!egg_test_start (test, "EggMarkdown")) -		return; - -	/************************************************************ -	 ****************        line_is_rule          ************** -	 ************************************************************/ -	ret = egg_markdown_to_text_line_is_rule ("* * *"); -	egg_test_title_assert (test, "is rule (1)", ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_rule ("***"); -	egg_test_title_assert (test, "is rule (2)", ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_rule ("*****"); -	egg_test_title_assert (test, "is rule (3)", ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_rule ("- - -"); -	egg_test_title_assert (test, "is rule (4)", ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_rule ("---------------------------------------"); -	egg_test_title_assert (test, "is rule (5)", ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_rule (""); -	egg_test_title_assert (test, "is rule (blank)", !ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_rule ("richard hughes"); -	egg_test_title_assert (test, "is rule (text)", !ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_rule ("- richard-hughes"); -	egg_test_title_assert (test, "is rule (bullet)", !ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_blank (""); -	egg_test_title_assert (test, "is blank (blank)", ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_blank (" \t "); -	egg_test_title_assert (test, "is blank (mix)", ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_blank ("richard hughes"); -	egg_test_title_assert (test, "is blank (name)", !ret); - -	/************************************************************/ -	ret = egg_markdown_to_text_line_is_blank ("ccccccccc"); -	egg_test_title_assert (test, "is blank (full)", !ret); - - -	/************************************************************ -	 ****************           replace            ************** -	 ************************************************************/ -	text = egg_markdown_replace ("summary -- really -- sure!", " -- ", " – "); -	egg_test_title (test, "replace (multiple)"); -	if (g_str_equal (text, "summary – really – sure!")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************ -	 ****************          formatter           ************** -	 ************************************************************/ -	text = egg_markdown_to_text_line_formatter ("**is important** text", "**", "<b>", "</b>"); -	egg_test_title (test, "formatter (left)"); -	if (g_str_equal (text, "<b>is important</b> text")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************/ -	text = egg_markdown_to_text_line_formatter ("this is **important**", "**", "<b>", "</b>"); -	egg_test_title (test, "formatter (right)"); -	if (g_str_equal (text, "this is <b>important</b>")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************/ -	text = egg_markdown_to_text_line_formatter ("**important**", "**", "<b>", "</b>"); -	egg_test_title (test, "formatter (only)"); -	if (g_str_equal (text, "<b>important</b>")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************/ -	text = egg_markdown_to_text_line_formatter ("***important***", "**", "<b>", "</b>"); -	egg_test_title (test, "formatter (only)"); -	if (g_str_equal (text, "<b>*important</b>*")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************/ -	text = egg_markdown_to_text_line_formatter ("I guess * this is * not bold", "*", "<i>", "</i>"); -	egg_test_title (test, "formatter (with spaces)"); -	if (g_str_equal (text, "I guess * this is * not bold")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************/ -	text = egg_markdown_to_text_line_formatter ("this **is important** text in **several** places", "**", "<b>", "</b>"); -	egg_test_title (test, "formatter (middle, multiple)"); -	if (g_str_equal (text, "this <b>is important</b> text in <b>several</b> places")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************/ -	text = egg_markdown_word_auto_format_code ("this is http://www.hughsie.com/with_spaces_in_url inline link"); -	egg_test_title (test, "auto formatter (url)"); -	if (g_str_equal (text, "this is `http://www.hughsie.com/with_spaces_in_url` inline link")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************/ -	text = egg_markdown_to_text_line_formatter ("this was \"triffic\" it was", "\"", "“", "”"); -	egg_test_title (test, "formatter (quotes)"); -	if (g_str_equal (text, "this was “triffic” it was")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************/ -	text = egg_markdown_to_text_line_formatter ("This isn't a present", "'", "‘", "’"); -	egg_test_title (test, "formatter (one quote)"); -	if (g_str_equal (text, "This isn't a present")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got %s", text); -	g_free (text); - -	/************************************************************ -	 ****************          markdown            ************** -	 ************************************************************/ -	egg_test_title (test, "get EggMarkdown object"); -	self = egg_markdown_new (); -	egg_test_assert (test, self != NULL); - -	/************************************************************/ -	ret = egg_markdown_set_output (self, EGG_MARKDOWN_OUTPUT_PANGO); -	egg_test_title_assert (test, "set pango output", ret); - -	/************************************************************/ -	markdown = "OEMs\n" -		   "====\n" -		   " - Bullett\n"; -	markdown_expected = -		   "<big>OEMs</big>\n" -		   "• Bullett"; -	egg_test_title (test, "markdown (type2 header)"); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - - -	/************************************************************/ -	markdown = "this is http://www.hughsie.com/with_spaces_in_url inline link\n"; -	markdown_expected = "this is <tt>http://www.hughsie.com/with_spaces_in_url</tt> inline link"; -	egg_test_title (test, "markdown (autocode)"); -	egg_markdown_set_autocode (self, TRUE); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	/************************************************************/ -	markdown = "*** This software is currently in alpha state ***\n"; -	markdown_expected = "<b><i> This software is currently in alpha state </b></i>"; -	egg_test_title (test, "markdown some invalid header"); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	/************************************************************/ -	markdown = " - This is a *very*\n" -		   "   short paragraph\n" -		   "   that is not usual.\n" -		   " - Another"; -	markdown_expected = -		   "• This is a <i>very</i> short paragraph that is not usual.\n" -		   "• Another"; -	egg_test_title (test, "markdown (complex1)"); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	/************************************************************/ -	markdown = "*  This is a *very*\n" -		   "   short paragraph\n" -		   "   that is not usual.\n" -		   "*  This is the second\n" -		   "   bullett point.\n" -		   "*  And the third.\n" -		   " \n" -		   "* * *\n" -		   " \n" -		   "Paragraph one\n" -		   "isn't __very__ long at all.\n" -		   "\n" -		   "Paragraph two\n" -		   "isn't much better."; -	markdown_expected = -		   "• This is a <i>very</i> short paragraph that is not usual.\n" -		   "• This is the second bullett point.\n" -		   "• And the third.\n" -		   "⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯\n" -		   "Paragraph one isn't <b>very</b> long at all.\n" -		   "Paragraph two isn't much better."; -	egg_test_title (test, "markdown (complex1)"); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	/************************************************************/ -	markdown = "This is a spec file description or\n" -		   "an **update** description in bohdi.\n" -		   "\n" -		   "* * *\n" -		   "# Big title #\n" -		   "\n" -		   "The *following* things 'were' fixed:\n" -		   "- Fix `dave`\n" -		   "* Fubar update because of \"security\"\n"; -	markdown_expected = -		   "This is a spec file description or an <b>update</b> description in bohdi.\n" -		   "⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯\n" -		   "<big>Big title</big>\n" -		   "The <i>following</i> things 'were' fixed:\n" -		   "• Fix <tt>dave</tt>\n" -		   "• Fubar update because of \"security\""; -	egg_test_title (test, "markdown (complex2)"); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	/************************************************************/ -	markdown = "* list seporated with spaces -\n" -		   "  first item\n" -		   "\n" -		   "* second item\n" -		   "\n" -		   "* third item\n"; -	markdown_expected = -		   "• list seporated with spaces - first item\n" -		   "• second item\n" -		   "• third item"; -	egg_test_title (test, "markdown (list with spaces)"); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	/************************************************************/ -	ret = egg_markdown_set_max_lines (self, 1); -	egg_test_title_assert (test, "set max_lines", ret); - -	/************************************************************/ -	markdown = "* list seporated with spaces -\n" -		   "  first item\n" -		   "* second item\n"; -	markdown_expected = -		   "• list seporated with spaces - first item"; -	egg_test_title (test, "markdown (one line limit)"); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	/************************************************************/ -	ret = egg_markdown_set_max_lines (self, 1); -	egg_test_title_assert (test, "set max_lines", ret); - -	/************************************************************/ -	markdown = "* list & spaces"; -	markdown_expected = -		   "• list & spaces"; -	egg_test_title (test, "markdown (escaping)"); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	/************************************************************/ -	egg_test_title (test, "markdown (free text)"); -	text = egg_markdown_parse (self, "This isn't a present"); -	if (g_str_equal (text, "This isn't a present")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s'", text); -	g_free (text); - -	/************************************************************/ -	egg_test_title (test, "markdown (autotext underscore)"); -	text = egg_markdown_parse (self, "This isn't CONFIG_UEVENT_HELPER_PATH present"); -	if (g_str_equal (text, "This isn't <tt>CONFIG_UEVENT_HELPER_PATH</tt> present")) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s'", text); -	g_free (text); - -	/************************************************************/ -	markdown = "*Thu Mar 12 12:00:00 2009* Dan Walsh <dwalsh@redhat.com> - 2.0.79-1\n" -		   "- Update to upstream \n" -		   " * Netlink socket handoff patch from Adam Jackson.\n" -		   " * AVC caching of compute_create results by Eric Paris.\n" -		   "\n" -		   "*Tue Mar 10 12:00:00 2009* Dan Walsh <dwalsh@redhat.com> - 2.0.78-5\n" -		   "- Add patch from ajax to accellerate X SELinux \n" -		   "- Update eparis patch\n"; -	markdown_expected = -		   "<i>Thu Mar 12 12:00:00 2009</i> Dan Walsh <tt><dwalsh@redhat.com></tt> - 2.0.79-1\n" -		   "• Update to upstream\n" -		   "• Netlink socket handoff patch from Adam Jackson.\n" -		   "• AVC caching of compute_create results by Eric Paris.\n" -		   "<i>Tue Mar 10 12:00:00 2009</i> Dan Walsh <tt><dwalsh@redhat.com></tt> - 2.0.78-5\n" -		   "• Add patch from ajax to accellerate X SELinux\n" -		   "• Update eparis patch"; -	egg_test_title (test, "markdown (end of bullett)"); -	egg_markdown_set_escape (self, TRUE); -	ret = egg_markdown_set_max_lines (self, 1024); -	text = egg_markdown_parse (self, markdown); -	if (g_str_equal (text, markdown_expected)) -		egg_test_success (test, NULL); -	else -		egg_test_failed (test, "failed, got '%s', expected '%s'", text, markdown_expected); -	g_free (text); - -	g_object_unref (self); - -	egg_test_end (test); -} -#endif - diff --git a/hardinfo2/help-viewer/help-viewer.c b/hardinfo2/help-viewer/help-viewer.c deleted file mode 100644 index ace6ef37..00000000 --- a/hardinfo2/help-viewer/help-viewer.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - *    HelpViewer - Simple Help file browser - *    Copyright (C) 2009 Leandro A. F. Pereira <leandro@hardinfo.org> - * - *    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, version 2. - * - *    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, write to the Free Software - *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA - */ - -#define _GNU_SOURCE		/* for strcasestr() */ -#include <string.h> -#include <stdlib.h> -#include <gtk/gtk.h> - -#include "config.h" -#include "shell.h" -#include "markdown-text-view.h" -#include "help-viewer.h" -#include "hardinfo.h" - -static void do_search(HelpViewer *hv, gchar *text); - -static void forward_clicked(GtkWidget *widget, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -    GSList *temp; -     -    /* puts the current file on the back stack */ -    hv->back_stack = g_slist_prepend(hv->back_stack, g_strdup(hv->current_file)); -     -    /* enables the back button */ -    gtk_widget_set_sensitive(hv->btn_back, TRUE); - -    /* loads the new current file */ -    if (g_str_has_prefix(hv->forward_stack->data, "search://")) { -        do_search(hv, hv->forward_stack->data + sizeof("search://") - 1); -    } else { -        markdown_textview_load_file(MARKDOWN_TEXTVIEW(hv->text_view), hv->forward_stack->data); -    } -     -    /* pops the stack */ -    temp = hv->forward_stack->next; -    g_free(hv->forward_stack->data); -    g_slist_free1(hv->forward_stack); -    hv->forward_stack = temp; -     -    /* if there aren't items on forward stack anymore, disables the button */ -    if (!hv->forward_stack) { -        gtk_widget_set_sensitive(hv->btn_forward, FALSE); -    } -} - -static void back_clicked(GtkWidget *widget, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -    GSList *temp; -     -    /* puts the current file on the forward stack */ -    hv->forward_stack = g_slist_prepend(hv->forward_stack, g_strdup(hv->current_file)); -     -    /* enables the forward button */ -    gtk_widget_set_sensitive(hv->btn_forward, TRUE); - -    /* loads the new current file */ -    if (g_str_has_prefix(hv->back_stack->data, "search://")) { -        do_search(hv, hv->back_stack->data + sizeof("search://") - 1); -    } else { -        markdown_textview_load_file(MARKDOWN_TEXTVIEW(hv->text_view), hv->back_stack->data); -    } -     -    /* pops the stack */ -    temp = hv->back_stack->next; -    g_free(hv->back_stack->data); -    g_slist_free1(hv->back_stack); -    hv->back_stack = temp; -     -    /* if there aren't items on back stack anymore, disables the button */ -    if (!hv->back_stack) { -        gtk_widget_set_sensitive(hv->btn_back, FALSE); -    } -} - -static void link_clicked(MarkdownTextView *text_view, gchar *link, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -     -    if (g_str_has_prefix(link, "http://")) { -        open_url(link); -    } else { -        /* adds the current file to the back stack (before loading the new file */ -        hv->back_stack = g_slist_prepend(hv->back_stack, g_strdup(hv->current_file)); -        gtk_widget_set_sensitive(hv->btn_back, TRUE); - -        gtk_statusbar_pop(GTK_STATUSBAR(hv->status_bar), 1); -        markdown_textview_load_file(text_view, link); -    } -} - -static void file_load_complete(MarkdownTextView *text_view, gchar *file, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -     -    /* sets the currently-loaded file */ -    g_free(hv->current_file); -    hv->current_file = g_strdup(file); -     -    gtk_statusbar_push(GTK_STATUSBAR(hv->status_bar), 1, "Done."); -} - -static void hovering_over_link(MarkdownTextView *text_view, gchar *link, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -    gchar *temp; -     -    temp = g_strconcat("Link to ", link, NULL); -     -    gtk_statusbar_push(GTK_STATUSBAR(hv->status_bar), 1, temp); -     -    g_free(temp); -} - -static void hovering_over_text(MarkdownTextView *text_view, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -     -    gtk_statusbar_pop(GTK_STATUSBAR(hv->status_bar), 1); -} - -static void do_search(HelpViewer *hv, gchar *text) -{ -    GString *markdown; -    GDir *dir; -    gchar **terms; -    gint no_results = 0; -    int term; -     -    /* -     * FIXME: This search is currently pretty slow; think on a better way to do search.  -     * Ideas: -     * - Build a index the first time the help file is opened -     * - Search only titles and subtitles -     */ -     -    terms = g_strsplit(text, " ", 0); -    markdown = g_string_new("# Search Results\n"); -    g_string_append_printf(markdown, "Search terms: *%s*\n****\n", text); -     -    gtk_widget_set_sensitive(hv->window, FALSE); -     -    if ((dir = g_dir_open(hv->help_directory, 0, NULL))) { -        const gchar *name; -         -        while ((name = g_dir_read_name(dir))) { -#if GTK_CHECK_VERSION(2,16,0) -            gtk_entry_progress_pulse(GTK_ENTRY(hv->text_search)); -#endif	/* GTK_CHECK_VERSION(2,16,0) */ -             -            if (g_str_has_suffix(name, ".hlp")) { -                FILE *file; -                gchar *path; -                gchar buffer[256]; -                 -                path = g_build_filename(hv->help_directory, name, NULL); -                if ((file = fopen(path, "rb"))) { -                    gboolean found = FALSE; -                    gchar *title = NULL; -                     -                    while (!found && fgets(buffer, sizeof buffer, file)) { -                        if (!title && (g_str_has_prefix(buffer, "# ") || g_str_has_prefix(buffer, " # "))) { -                            title = g_strstrip(strchr(buffer, '#') + 1); -                            title = g_strdup(title); -                        } -                         -                        for (term = 0; !found && terms[term]; term++) { -#ifdef strcasestr -                            found = strcasestr(buffer, terms[term]) != NULL; -#else -                            gchar *upper1, *upper2; -                             -                            upper1 = g_utf8_strup(buffer, -1); -                            upper2 = g_utf8_strup(terms[term], -1); -                             -                            found = strstr(upper1, upper2) != NULL; -                             -                            g_free(upper1); -                            g_free(upper2); -#endif -                        } -                    } -                     -                    if (found) { -                        no_results++; -                         -                        if (title) { -                              g_string_append_printf(markdown, -                                                     "* [%s %s]\n", name, title); -                        } else { -                              g_string_append_printf(markdown, -                                                     "* [%s %s]\n", name, name); -                        } -                    } -                     -                    g_free(title); -                    fclose(file); -                } -                 -                g_free(path); -            } -        } -         -        g_dir_close(dir); -    } -     -     -    if (no_results == 0) { -        g_string_append_printf(markdown, -                               "Search returned no results."); -    } else { -        g_string_append_printf(markdown, -                               "****\n%d results found.", no_results); -    } -     -    /* shows the results inside the textview */ -    markdown_textview_set_text(MARKDOWN_TEXTVIEW(hv->text_view), markdown->str); - -    g_free(hv->current_file); -    hv->current_file = g_strdup_printf("search://%s", text); - -#if GTK_CHECK_VERSION(2,16,0) -    gtk_entry_set_progress_fraction(GTK_ENTRY(hv->text_search), 0.0f); -#endif	/* GTK_CHECK_VERSION(2,16,0) */ -    gtk_widget_set_sensitive(hv->window, TRUE); - -    g_string_free(markdown, TRUE); -    g_strfreev(terms); -} - -static void activate(GtkEntry *entry, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -     -    /* adds the current file to the back stack (before loading the new file */ -    hv->back_stack = g_slist_prepend(hv->back_stack, g_strdup(hv->current_file)); -    gtk_widget_set_sensitive(hv->btn_back, TRUE); - -    do_search((HelpViewer *)data, (gchar *)gtk_entry_get_text(entry)); -} - -#if GTK_CHECK_VERSION(2,16,0) -static void icon_press(GtkEntry *entry, gint position, -                       GdkEventButton *event, gpointer data) -{ -    if (position == GTK_ENTRY_ICON_SECONDARY) -        activate(entry, data); -} -#endif	/* GTK_CHECK_VERSION(2,16,0) */  - -static void home_clicked(GtkWidget *button, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -     -    help_viewer_open_page(hv, "index.hlp"); -} - -void help_viewer_open_page(HelpViewer *hv, const gchar *page) -{ -    gchar *temp; -     -    temp = g_strdup(hv->current_file); -     -    if (!markdown_textview_load_file(MARKDOWN_TEXTVIEW(hv->text_view), page)) { -        GtkWidget	*dialog; -        Shell		*shell; -         -        shell = shell_get_main_shell(); -        dialog = gtk_message_dialog_new(GTK_WINDOW(shell->window), -                                        GTK_DIALOG_DESTROY_WITH_PARENT, -                                        GTK_MESSAGE_ERROR, -                                        GTK_BUTTONS_CLOSE, -                                        "Cannot open help file (%s).", -                                        page); -        gtk_dialog_run(GTK_DIALOG(dialog)); -        gtk_widget_destroy(dialog); -         -        g_free(temp); -    } else { -        /* adds the current file to the back stack (before loading the new file */ -        hv->back_stack = g_slist_prepend(hv->back_stack, temp); -        gtk_widget_set_sensitive(hv->btn_back, TRUE); -        gtk_window_present(GTK_WINDOW(hv->window)); -    } -} - -void help_viewer_destroy(HelpViewer *hv) -{ -    Shell *shell; -    GSList *item; - -    for (item = hv->back_stack; item; item = item->next) { -        g_free(item->data); -    } - -    for (item = hv->forward_stack; item; item = item->next) { -        g_free(item->data); -    } -     -    g_slist_free(hv->back_stack); -    g_slist_free(hv->forward_stack); - -    g_free(hv->current_file); -    g_free(hv->help_directory); -     -    shell = shell_get_main_shell(); -    shell->help_viewer = NULL; -} - -static gboolean destroy_me(GtkWidget *widget, gpointer data) -{ -    HelpViewer *hv = (HelpViewer *)data; -     -    help_viewer_destroy(hv); - -    return FALSE; -} - -HelpViewer * -help_viewer_new (const gchar *help_dir, const gchar *help_file) -{ -    Shell *shell; -    HelpViewer *hv; -    GtkWidget *help_viewer; -    GtkWidget *vbox; -    GtkWidget *hbox; -    GtkWidget *toolbar1; -    GtkIconSize tmp_toolbar_icon_size; -    GtkWidget *btn_back; -    GtkWidget *btn_forward; -    GtkWidget *separatortoolitem1; -    GtkWidget *toolbar2; -    GtkWidget *toolitem3; -#if !GTK_CHECK_VERSION(2,16,0) -    GtkWidget *label1; -#endif	/* GTK_CHECK_VERSION(2,16,0) */ -    GtkWidget *toolitem4; -    GtkWidget *txt_search; -    GtkWidget *scrolledhelp_viewer; -    GtkWidget *markdown_textview; -    GtkWidget *status_bar; -    GtkWidget *btn_home; -    GdkPixbuf *icon; -     -    shell = shell_get_main_shell(); - -    help_viewer = gtk_window_new(GTK_WINDOW_TOPLEVEL); -    gtk_widget_set_size_request(help_viewer, 300, 200); -    gtk_window_set_default_size(GTK_WINDOW(help_viewer), 640, 480); -    gtk_window_set_title(GTK_WINDOW(help_viewer), "Help Viewer"); -    gtk_window_set_transient_for(GTK_WINDOW(help_viewer), GTK_WINDOW(shell->window)); -     -    icon = gtk_widget_render_icon(help_viewer, GTK_STOCK_HELP,  -                                  GTK_ICON_SIZE_DIALOG, -                                  NULL); -    gtk_window_set_icon(GTK_WINDOW(help_viewer), icon); -    g_object_unref(icon); -     -    vbox = gtk_vbox_new (FALSE, 0); -    gtk_widget_show (vbox); -    gtk_container_add (GTK_CONTAINER (help_viewer), vbox); - -    hbox = gtk_hbox_new (FALSE, 0); -    gtk_widget_show (hbox); -    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - -    toolbar1 = gtk_toolbar_new (); -    gtk_widget_show (toolbar1); -    gtk_box_pack_start (GTK_BOX (hbox), toolbar1, TRUE, TRUE, 0); -    gtk_toolbar_set_style (GTK_TOOLBAR (toolbar1), GTK_TOOLBAR_BOTH_HORIZ); -    tmp_toolbar_icon_size = gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar1)); - -    btn_back = (GtkWidget*) gtk_tool_button_new_from_stock ("gtk-go-back"); -    gtk_widget_show (btn_back); -    gtk_container_add (GTK_CONTAINER (toolbar1), btn_back); -    gtk_tool_item_set_is_important (GTK_TOOL_ITEM (btn_back), TRUE); -    gtk_widget_set_sensitive(btn_back, FALSE); - -    btn_forward = (GtkWidget*) gtk_tool_button_new_from_stock ("gtk-go-forward"); -    gtk_widget_show (btn_forward); -    gtk_container_add (GTK_CONTAINER (toolbar1), btn_forward); -    gtk_widget_set_sensitive(btn_forward, FALSE); - -    separatortoolitem1 = (GtkWidget*) gtk_separator_tool_item_new (); -    gtk_widget_show (separatortoolitem1); -    gtk_container_add (GTK_CONTAINER (toolbar1), separatortoolitem1); - -    btn_home = (GtkWidget*) gtk_tool_button_new_from_stock ("gtk-home"); -    gtk_widget_show (btn_home); -    gtk_container_add (GTK_CONTAINER (toolbar1), btn_home); - -    toolbar2 = gtk_toolbar_new (); -    gtk_widget_show (toolbar2); -    gtk_box_pack_end (GTK_BOX (hbox), toolbar2, FALSE, TRUE, 0); -    gtk_toolbar_set_style (GTK_TOOLBAR (toolbar2), GTK_TOOLBAR_BOTH_HORIZ); -    gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar2), FALSE); -    tmp_toolbar_icon_size = gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar2)); - -    toolitem3 = (GtkWidget*) gtk_tool_item_new (); -    gtk_widget_show (toolitem3); -    gtk_container_add (GTK_CONTAINER (toolbar2), toolitem3); - -#if !GTK_CHECK_VERSION(2,16,0) -    label1 = gtk_label_new_with_mnemonic ("_Search:"); -    gtk_widget_show (label1); -    gtk_container_add (GTK_CONTAINER (toolitem3), label1); -#endif	/* GTK_CHECK_VERSION(2,16,0) */ - -    toolitem4 = (GtkWidget*) gtk_tool_item_new (); -    gtk_widget_show (toolitem4); -    gtk_container_add (GTK_CONTAINER (toolbar2), toolitem4); - -    txt_search = gtk_entry_new (); -    gtk_widget_show (txt_search); -    gtk_container_add (GTK_CONTAINER (toolitem4), txt_search); -    gtk_entry_set_invisible_char (GTK_ENTRY (txt_search), 9679); -#if GTK_CHECK_VERSION(2,16,0) -    gtk_entry_set_icon_from_stock(GTK_ENTRY(txt_search), -                                  GTK_ENTRY_ICON_SECONDARY, -                                  GTK_STOCK_FIND); -#endif	/* GTK_CHECK_VERSION(2,16,0) */ - -    scrolledhelp_viewer = gtk_scrolled_window_new (NULL, NULL); -    gtk_widget_show (scrolledhelp_viewer); -    gtk_box_pack_start (GTK_BOX (vbox), scrolledhelp_viewer, TRUE, TRUE, 0); -    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledhelp_viewer), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - -    markdown_textview = markdown_textview_new(); -    markdown_textview_set_image_directory(MARKDOWN_TEXTVIEW(markdown_textview), help_dir); -    gtk_widget_show (markdown_textview); -    gtk_container_add (GTK_CONTAINER (scrolledhelp_viewer), markdown_textview); - -    status_bar = gtk_statusbar_new (); -    gtk_widget_show (status_bar); -    gtk_box_pack_start (GTK_BOX (vbox), status_bar, FALSE, FALSE, 0); - -    hv = g_new0(HelpViewer, 1); -    hv->window = help_viewer; -    hv->status_bar = status_bar; -    hv->btn_back = btn_back; -    hv->btn_forward = btn_forward; -    hv->text_view = markdown_textview; -    hv->text_search = txt_search; -    hv->help_directory = g_strdup(help_dir); -    hv->back_stack = NULL; -    hv->forward_stack = NULL; - -    g_signal_connect(markdown_textview, "link-clicked", G_CALLBACK(link_clicked), hv); -    g_signal_connect(markdown_textview, "hovering-over-link", G_CALLBACK(hovering_over_link), hv); -    g_signal_connect(markdown_textview, "hovering-over-text", G_CALLBACK(hovering_over_text), hv); -    g_signal_connect(markdown_textview, "file-load-complete", G_CALLBACK(file_load_complete), hv); - -    g_signal_connect(btn_back, "clicked", G_CALLBACK(back_clicked), hv); -    g_signal_connect(btn_forward, "clicked", G_CALLBACK(forward_clicked), hv); -    g_signal_connect(btn_home, "clicked", G_CALLBACK(home_clicked), hv); - -    g_signal_connect(help_viewer, "delete-event", G_CALLBACK(destroy_me), hv); -    g_signal_connect(txt_search, "activate", G_CALLBACK(activate), hv); - -#if GTK_CHECK_VERSION(2,16,0) -    g_signal_connect(txt_search, "icon-press", G_CALLBACK(icon_press), hv); -#endif	/* GTK_CHECK_VERSION(2,16,0) */ -                             -    if (!markdown_textview_load_file(MARKDOWN_TEXTVIEW(markdown_textview), help_file ? help_file : "index.hlp")) { -        GtkWidget	*dialog; - -        dialog = gtk_message_dialog_new(GTK_WINDOW(shell->window), -                                        GTK_DIALOG_DESTROY_WITH_PARENT, -                                        GTK_MESSAGE_ERROR, -                                        GTK_BUTTONS_CLOSE, -                                        "Cannot open help file (%s).", -                                        help_file ? help_file : "index.hlp"); -        gtk_dialog_run(GTK_DIALOG(dialog)); -        gtk_widget_destroy(dialog); -         -        gtk_widget_destroy(hv->window); -        g_free(hv); -         -        return NULL; -    } -     -    gtk_widget_show_all(hv->window); - -    return hv; -} - -#ifdef HELPVIEWER_TEST -int main(int argc, char **argv) -{ -    HelpViewer *hv; -     -    gtk_init(&argc, &argv); -     -    hv = help_viewer_new("documentation", NULL); -     -    gtk_main(); -} -#endif	/* HELPVIEWER_TEST */ diff --git a/hardinfo2/help-viewer/markdown-text-view.c b/hardinfo2/help-viewer/markdown-text-view.c deleted file mode 100644 index 6bfcc131..00000000 --- a/hardinfo2/help-viewer/markdown-text-view.c +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Markdown Text View - * GtkTextView subclass that supports Markdown syntax - * - * Copyright (C) 2009 Leandro Pereira <leandro@hardinfo.org> - * Portions Copyright (C) 2007-2008 Richard Hughes <richard@hughsie.com> - * Portions Copyright (C) GTK+ Team (based on hypertext textview demo) - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#include <stdlib.h> -#include <gdk/gdkkeysyms.h> - -#include "markdown-text-view.h" -#include "config.h" - -static GdkCursor *hand_cursor = NULL; - -G_DEFINE_TYPE(MarkdownTextView, markdown_textview, GTK_TYPE_TEXT_VIEW); - -enum { -     LINK_CLICKED, -     HOVERING_OVER_LINK, -     HOVERING_OVER_TEXT, -     FILE_LOAD_COMPLETE, -     LAST_SIGNAL -}; - -static guint markdown_textview_signals[LAST_SIGNAL] = { 0 }; - -GtkWidget *markdown_textview_new() -{ -    return g_object_new(TYPE_MARKDOWN_TEXTVIEW, NULL); -} - -static void markdown_textview_class_init(MarkdownTextViewClass * klass) -{ -    GObjectClass *object_class; - -    if (!hand_cursor) { -	hand_cursor = gdk_cursor_new(GDK_HAND2); -    } - -    object_class = G_OBJECT_CLASS(klass); - -    markdown_textview_signals[LINK_CLICKED] = g_signal_new( -             "link-clicked", -             G_OBJECT_CLASS_TYPE(object_class), -             G_SIGNAL_RUN_FIRST, -             G_STRUCT_OFFSET(MarkdownTextViewClass, link_clicked), -             NULL, NULL, -             g_cclosure_marshal_VOID__STRING, -             G_TYPE_NONE, -             1, -             G_TYPE_STRING); - -    markdown_textview_signals[HOVERING_OVER_LINK] = g_signal_new( -             "hovering-over-link", -             G_OBJECT_CLASS_TYPE(object_class), -             G_SIGNAL_RUN_FIRST, -             G_STRUCT_OFFSET(MarkdownTextViewClass, hovering_over_link), -             NULL, NULL, -             g_cclosure_marshal_VOID__STRING, -             G_TYPE_NONE, -             1, -             G_TYPE_STRING); - -    markdown_textview_signals[HOVERING_OVER_TEXT] = g_signal_new( -             "hovering-over-text", -             G_OBJECT_CLASS_TYPE(object_class), -             G_SIGNAL_RUN_FIRST, -             G_STRUCT_OFFSET(MarkdownTextViewClass, hovering_over_text), -             NULL, NULL, -             g_cclosure_marshal_VOID__VOID, -             G_TYPE_NONE, -             0); - -    markdown_textview_signals[FILE_LOAD_COMPLETE] = g_signal_new( -             "file-load-complete", -             G_OBJECT_CLASS_TYPE(object_class), -             G_SIGNAL_RUN_FIRST, -             G_STRUCT_OFFSET(MarkdownTextViewClass, file_load_complete), -             NULL, NULL, -             g_cclosure_marshal_VOID__STRING, -             G_TYPE_NONE, -             1, -             G_TYPE_STRING); -} - -static void -gtk_text_buffer_insert_markup(GtkTextBuffer * buffer, GtkTextIter * iter, -			      const gchar * markup) -{ -    PangoAttrIterator *paiter; -    PangoAttrList *attrlist; -    GtkTextMark *mark; -    GError *error = NULL; -    gchar *text; - -    g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); -    g_return_if_fail(markup != NULL); - -    if (*markup == '\000') -	return; - -    /* invalid */ -    if (!pango_parse_markup(markup, -1, 0, &attrlist, &text, NULL, &error)) { -	g_warning("Invalid markup string: %s", error->message); -	g_error_free(error); -	return; -    } - -    /* trivial, no markup */ -    if (attrlist == NULL) { -	gtk_text_buffer_insert(buffer, iter, text, -1); -	g_free(text); -	return; -    } - -    /* create mark with right gravity */ -    mark = gtk_text_buffer_create_mark(buffer, NULL, iter, FALSE); -    paiter = pango_attr_list_get_iterator(attrlist); - -    do { -	PangoAttribute *attr; -	GtkTextTag *tag; -	GtkTextTag *tag_para; -	gint start, end; - -	pango_attr_iterator_range(paiter, &start, &end); - -	if (end == G_MAXINT)	/* last chunk */ -	    end = start - 1;	/* resulting in -1 to be passed to _insert */ - -	tag = gtk_text_tag_new(NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_LANGUAGE))) -	    g_object_set(tag, "language", -			 pango_language_to_string(((PangoAttrLanguage *) -						   attr)->value), NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_FAMILY))) -	    g_object_set(tag, "family", ((PangoAttrString *) attr)->value, -			 NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_STYLE))) -	    g_object_set(tag, "style", ((PangoAttrInt *) attr)->value, -			 NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_WEIGHT))) -	    g_object_set(tag, "weight", ((PangoAttrInt *) attr)->value, -			 NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_VARIANT))) -	    g_object_set(tag, "variant", ((PangoAttrInt *) attr)->value, -			 NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_STRETCH))) -	    g_object_set(tag, "stretch", ((PangoAttrInt *) attr)->value, -			 NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_SIZE))) -	    g_object_set(tag, "size", ((PangoAttrInt *) attr)->value, -			 NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_FONT_DESC))) -	    g_object_set(tag, "font-desc", -			 ((PangoAttrFontDesc *) attr)->desc, NULL); - -	if ((attr = -	     pango_attr_iterator_get(paiter, PANGO_ATTR_FOREGROUND))) { -	    GdkColor col = { 0, -		((PangoAttrColor *) attr)->color.red, -		((PangoAttrColor *) attr)->color.green, -		((PangoAttrColor *) attr)->color.blue -	    }; - -	    g_object_set(tag, "foreground-gdk", &col, NULL); -	} - -	if ((attr = -	     pango_attr_iterator_get(paiter, PANGO_ATTR_BACKGROUND))) { -	    GdkColor col = { 0, -		((PangoAttrColor *) attr)->color.red, -		((PangoAttrColor *) attr)->color.green, -		((PangoAttrColor *) attr)->color.blue -	    }; - -	    g_object_set(tag, "background-gdk", &col, NULL); -	} - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_UNDERLINE))) -	    g_object_set(tag, "underline", ((PangoAttrInt *) attr)->value, -			 NULL); - -	if ((attr = -	     pango_attr_iterator_get(paiter, PANGO_ATTR_STRIKETHROUGH))) -	    g_object_set(tag, "strikethrough", -			 (gboolean) (((PangoAttrInt *) attr)->value != 0), -			 NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_RISE))) -	    g_object_set(tag, "rise", ((PangoAttrInt *) attr)->value, -			 NULL); - -	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_SCALE))) -	    g_object_set(tag, "scale", ((PangoAttrFloat *) attr)->value, -			 NULL); - -	gtk_text_tag_table_add(gtk_text_buffer_get_tag_table(buffer), tag); - -	tag_para = -	    gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table -				      (buffer), "para"); -	gtk_text_buffer_insert_with_tags(buffer, iter, text + start, -					 end - start, tag, tag_para, NULL); - -	/* mark had right gravity, so it should be -	 *      at the end of the inserted text now */ -	gtk_text_buffer_get_iter_at_mark(buffer, iter, mark); -    } while (pango_attr_iterator_next(paiter)); - -    gtk_text_buffer_delete_mark(buffer, mark); -    pango_attr_iterator_destroy(paiter); -    pango_attr_list_unref(attrlist); -    g_free(text); -} - - -static void -set_cursor_if_appropriate(MarkdownTextView * self, gint x, gint y) -{ -    GSList *tags = NULL, *tagp = NULL; -    GtkTextIter iter; -    gboolean hovering = FALSE; -    gchar *link_uri = NULL; - -    gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(self), &iter, x, -				       y); - -    tags = gtk_text_iter_get_tags(&iter); -    for (tagp = tags; tagp != NULL; tagp = tagp->next) { -	GtkTextTag *tag = tagp->data; -	gint is_underline = 0; -	gchar *lang = NULL; - -	g_object_get(G_OBJECT(tag), -		     "underline", &is_underline, -		     "language", &lang, -		     NULL); - -	if (is_underline == 1 && lang) { -	    link_uri = egg_markdown_get_link_uri(self->markdown, atoi(lang)); -	    g_free(lang); -	    hovering = TRUE; -	    break; -	} - -	g_free(lang); -    } - -    if (hovering != self->hovering_over_link) { -	self->hovering_over_link = hovering; - -	if (self->hovering_over_link) { -            g_signal_emit(self, markdown_textview_signals[HOVERING_OVER_LINK], -                          0, link_uri); -	    gdk_window_set_cursor(gtk_text_view_get_window -				  (GTK_TEXT_VIEW(self), -				   GTK_TEXT_WINDOW_TEXT), hand_cursor); -	} else { -            g_signal_emit(self, markdown_textview_signals[HOVERING_OVER_TEXT], 0); -	    gdk_window_set_cursor(gtk_text_view_get_window -				  (GTK_TEXT_VIEW(self), -				   GTK_TEXT_WINDOW_TEXT), NULL); -        } -    } -     -    if (link_uri) -        g_free(link_uri); - -    if (tags) -	g_slist_free(tags); -} - -/* Update the cursor image if the pointer moved.  - */ -static gboolean -motion_notify_event(GtkWidget * self, GdkEventMotion * event) -{ -    gint x, y; - -    gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(self), -					  GTK_TEXT_WINDOW_WIDGET, -					  event->x, event->y, &x, &y); - -    set_cursor_if_appropriate(MARKDOWN_TEXTVIEW(self), x, y); - -    gdk_window_get_pointer(self->window, NULL, NULL, NULL); -    return FALSE; -} - -/* Also update the cursor image if the window becomes visible - * (e.g. when a window covering it got iconified). - */ -static gboolean -visibility_notify_event(GtkWidget * self, GdkEventVisibility * event) -{ -    gint wx, wy, bx, by; - -    gdk_window_get_pointer(self->window, &wx, &wy, NULL); - -    gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(self), -					  GTK_TEXT_WINDOW_WIDGET, -					  wx, wy, &bx, &by); - -    set_cursor_if_appropriate(MARKDOWN_TEXTVIEW(self), bx, by); - -    return FALSE; -} - -static void -follow_if_link(GtkWidget * widget, GtkTextIter * iter) -{ -    GSList *tags = NULL, *tagp = NULL; -    MarkdownTextView *self = MARKDOWN_TEXTVIEW(widget); -     -    tags = gtk_text_iter_get_tags(iter); -    for (tagp = tags; tagp != NULL; tagp = tagp->next) { -	GtkTextTag *tag = tagp->data; -	gint is_underline = 0; -	gchar *lang = NULL; - -	g_object_get(G_OBJECT(tag), -		     "underline", &is_underline, -		     "language", &lang, -		     NULL); - -	if (is_underline == 1 && lang) { -	    gchar *link = egg_markdown_get_link_uri(self->markdown, atoi(lang)); -	    if (link) { -	        g_signal_emit(self, markdown_textview_signals[LINK_CLICKED], -                              0, link); -		g_free(link); -	    } -	    g_free(lang); -	    break; -	} - -	g_free(lang); -    } - -    if (tags) -	g_slist_free(tags); -} - -static gboolean -key_press_event(GtkWidget * self, -		GdkEventKey * event) -{ -    GtkTextIter iter; -    GtkTextBuffer *buffer; - -    switch (event->keyval) { -    case GDK_Return: -    case GDK_KP_Enter: -	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); -	gtk_text_buffer_get_iter_at_mark(buffer, &iter, -					 gtk_text_buffer_get_insert -					 (buffer)); -	follow_if_link(self, &iter); -	break; - -    default: -	break; -    } - -    return FALSE; -} - -static gboolean -event_after(GtkWidget * self, GdkEvent * ev) -{ -    GtkTextIter start, end, iter; -    GtkTextBuffer *buffer; -    GdkEventButton *event; -    gint x, y; - -    if (ev->type != GDK_BUTTON_RELEASE) -	return FALSE; - -    event = (GdkEventButton *) ev; - -    if (event->button != 1) -	return FALSE; - -    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); - -    /* we shouldn't follow a link if the user has selected something */ -    gtk_text_buffer_get_selection_bounds(buffer, &start, &end); -    if (gtk_text_iter_get_offset(&start) != gtk_text_iter_get_offset(&end)) -	return FALSE; - -    gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(self), -					  GTK_TEXT_WINDOW_WIDGET, -					  event->x, event->y, &x, &y); - -    gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(self), &iter, x, -				       y); - -    follow_if_link(self, &iter); - -    return FALSE; -} - -void -markdown_textview_clear(MarkdownTextView * self) -{ -    GtkTextBuffer *text_buffer; -     -    g_return_if_fail(IS_MARKDOWN_TEXTVIEW(self)); - -    egg_markdown_clear(self->markdown); - -    text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); -    gtk_text_buffer_set_text(text_buffer, "\n", 1); -} - -static void -load_images(MarkdownTextView * self) -{ -    GtkTextBuffer *buffer; -    GtkTextIter iter; -    GSList *tags, *tagp; -    gchar *image_path; -     -    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); -    gtk_text_buffer_get_start_iter(buffer, &iter); -     -    do { -       tags = gtk_text_iter_get_tags(&iter); -       for (tagp = tags; tagp != NULL; tagp = tagp->next) { -           GtkTextTag *tag = tagp->data; -           gint is_underline = 0; -           gchar *lang = NULL; - -           g_object_get(G_OBJECT(tag), -                        "underline", &is_underline, -                        "language", &lang, -                        NULL); - -           if (is_underline == 2 && lang) { -               GdkPixbuf *pixbuf; -               gchar *path; -                -               image_path = egg_markdown_get_link_uri(self->markdown, atoi(lang)); -               path = g_build_filename(self->image_directory, image_path, NULL); -               pixbuf = gdk_pixbuf_new_from_file(path, NULL); -               if (pixbuf) { -                   GtkTextMark *mark; -                   GtkTextIter start; - -                   mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, FALSE); -                    -                   gtk_text_buffer_get_iter_at_mark(buffer, &start, mark); -                   gtk_text_iter_forward_to_tag_toggle(&iter, tag); -                   gtk_text_buffer_delete(buffer, &start, &iter); - -                   gtk_text_buffer_insert_pixbuf(buffer, &iter, pixbuf); -   -                   g_object_unref(pixbuf); -                   gtk_text_buffer_delete_mark(buffer, mark); -               } -                -               g_free(image_path); -               g_free(lang); -               g_free(path); -               break; -           } - -           g_free(lang); -       } -        -       if (tags) -           g_slist_free(tags); -   } while (gtk_text_iter_forward_to_tag_toggle(&iter, NULL)); -} - -static gboolean -append_text(MarkdownTextView * self, -            const gchar * text) -{ -    GtkTextIter iter; -    GtkTextBuffer *text_buffer; -    gchar *line; -     -    g_return_val_if_fail(IS_MARKDOWN_TEXTVIEW(self), FALSE); -     -    text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); -    gtk_text_buffer_get_end_iter(text_buffer, &iter); - -    line = egg_markdown_parse(self->markdown, text); -    if (line && *line) { -        gtk_text_buffer_insert_markup(text_buffer, &iter, line); -        gtk_text_buffer_insert(text_buffer, &iter, "\n", 1); -        g_free(line); -         -        return TRUE; -    } -     -    return FALSE; -} - -gboolean -markdown_textview_set_text(MarkdownTextView * self, -                           const gchar * text) -{ -    gboolean result = TRUE; -    gchar **lines; -    gint line; -     -    g_return_val_if_fail(IS_MARKDOWN_TEXTVIEW(self), FALSE); - -    markdown_textview_clear(self); -     -    lines = g_strsplit(text, "\n", 0); -    for (line = 0; result && lines[line]; line++) { -         result = append_text(self, (const gchar *)lines[line]); -    } -    g_strfreev(lines); - -    load_images(self); -     -    return result; -}                            - -gboolean -markdown_textview_load_file(MarkdownTextView * self, -			    const gchar * file_name) -{ -    FILE *text_file; -    gchar *path; - -    g_return_val_if_fail(IS_MARKDOWN_TEXTVIEW(self), FALSE); -     -    path = g_build_filename(self->image_directory, file_name, NULL); - -    /* we do assume UTF-8 encoding */ -    if ((text_file = fopen(path, "rb"))) { -	GtkTextBuffer *text_buffer; -	GtkTextIter iter; -	gchar *line; -	gchar buffer[EGG_MARKDOWN_MAX_LINE_LENGTH]; - -	text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); - -	gtk_text_buffer_set_text(text_buffer, "\n", 1); -	gtk_text_buffer_get_start_iter(text_buffer, &iter); - -	egg_markdown_clear(self->markdown); - -	while (fgets(buffer, EGG_MARKDOWN_MAX_LINE_LENGTH, text_file)) { -	    line = egg_markdown_parse(self->markdown, buffer); - -	    if (line && *line) { -		gtk_text_buffer_insert_markup(text_buffer, &iter, line); -		gtk_text_buffer_insert(text_buffer, &iter, "\n", 1); -	    } - -	    g_free(line); -	} -	fclose(text_file); -	 -	load_images(self); -	 -        g_signal_emit(self, markdown_textview_signals[FILE_LOAD_COMPLETE], 0, file_name); -         -        g_free(path); - -	return TRUE; -    } -     -    g_free(path); - -    return FALSE; -} - -void -markdown_textview_set_image_directory(MarkdownTextView * self, const gchar *directory) -{ -    g_return_if_fail(IS_MARKDOWN_TEXTVIEW(self)); - -    g_free(self->image_directory); -    self->image_directory = g_strdup(directory); -} - -static void markdown_textview_init(MarkdownTextView * self) -{ -    self->markdown = egg_markdown_new(); -    self->image_directory = g_strdup("."); - -    egg_markdown_set_output(self->markdown, EGG_MARKDOWN_OUTPUT_PANGO); -    egg_markdown_set_escape(self->markdown, TRUE); -    egg_markdown_set_autocode(self->markdown, TRUE); -    egg_markdown_set_smart_quoting(self->markdown, TRUE); - -    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(self), GTK_WRAP_WORD); -    gtk_text_view_set_editable(GTK_TEXT_VIEW(self), FALSE); -    gtk_text_view_set_left_margin(GTK_TEXT_VIEW(self), 10); -    gtk_text_view_set_right_margin(GTK_TEXT_VIEW(self), 10); -    gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(self), 3); -    gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(self), 3); -     -    g_signal_connect(self, "event-after", -		     G_CALLBACK(event_after), NULL); -    g_signal_connect(self, "key-press-event", -		     G_CALLBACK(key_press_event), NULL); -    g_signal_connect(self, "motion-notify-event", -		     G_CALLBACK(motion_notify_event), NULL); -    g_signal_connect(self, "visibility-notify-event", -		     G_CALLBACK(visibility_notify_event), NULL); -} -  | 
