Skip to content

Commit

Permalink
Markdown: Allow exporting Markdown as HTML (#502)
Browse files Browse the repository at this point in the history
* Markdown: Allow exporting Markdown as HTML

Add a Tools menu item "Export Markdown as HTML" to allow saving of the
rendered HTML to disk instead of just the live preview.

Closes #497

* Markdown: improve Export to HTML feature

* Use the document's filename as the basis for the new HTML filename.
* Properly setup the initial directory and suggested filename in the
  file chooser.
* Re-run the file chooser after showing error message if saving fails.
  • Loading branch information
codebrainz authored and frlan committed Nov 13, 2016
1 parent f1c09c4 commit 6e3de19
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 1 deletion.
91 changes: 91 additions & 0 deletions markdown/src/plugin.c
Expand Up @@ -48,13 +48,15 @@ PLUGIN_SET_TRANSLATABLE_INFO(LOCALEDIR, GETTEXT_PACKAGE,
/* Global data */
static MarkdownViewer *g_viewer = NULL;
static GtkWidget *g_scrolled_win = NULL;
static GtkWidget *g_export_html = NULL;

/* Forward declarations */
static void update_markdown_viewer(MarkdownViewer *viewer);
static gboolean on_editor_notify(GObject *obj, GeanyEditor *editor, SCNotification *notif, MarkdownViewer *viewer);
static void on_document_signal(GObject *obj, GeanyDocument *doc, MarkdownViewer *viewer);
static void on_document_filetype_set(GObject *obj, GeanyDocument *doc, GeanyFiletype *ft_old, MarkdownViewer *viewer);
static void on_view_pos_notify(GObject *obj, GParamSpec *pspec, MarkdownViewer *viewer);
static void on_export_as_html_activate(GtkMenuItem *item, MarkdownViewer *viewer);

/* Main plugin entry point on plugin load. */
void plugin_init(GeanyData *data)
Expand Down Expand Up @@ -97,6 +99,11 @@ void plugin_init(GeanyData *data)

g_signal_connect(conf, "notify::view-pos", G_CALLBACK(on_view_pos_notify), viewer);

g_export_html = gtk_menu_item_new_with_label(_("Export Markdown as HTML..."));
gtk_menu_shell_append(GTK_MENU_SHELL(data->main_widgets->tools_menu), g_export_html);
g_signal_connect(g_export_html, "activate", G_CALLBACK(on_export_as_html_activate), viewer);
gtk_widget_show(g_export_html);

#define MD_PSC(sig, cb) \
plugin_signal_connect(geany_plugin, NULL, (sig), TRUE, G_CALLBACK(cb), viewer)
/* Geany takes care of disconnecting these for us when the plugin is unloaded,
Expand All @@ -119,6 +126,7 @@ void plugin_init(GeanyData *data)
/* Cleanup resources on plugin unload. */
void plugin_cleanup(void)
{
gtk_widget_destroy(g_export_html);
gtk_widget_destroy(g_scrolled_win);
}

Expand Down Expand Up @@ -162,9 +170,11 @@ update_markdown_viewer(MarkdownViewer *viewer)
gchar *text;
text = (gchar*) scintilla_send_message(doc->editor->sci, SCI_GETCHARACTERPOINTER, 0, 0);
markdown_viewer_set_markdown(viewer, text, doc->encoding);
gtk_widget_set_sensitive(g_export_html, TRUE);
} else {
markdown_viewer_set_markdown(viewer,
_("The current document does not have a Markdown filetype."), "UTF-8");
gtk_widget_set_sensitive(g_export_html, FALSE);
}

markdown_viewer_queue_update(viewer);
Expand Down Expand Up @@ -240,3 +250,84 @@ on_view_pos_notify(GObject *obj, GParamSpec *pspec, MarkdownViewer *viewer)

update_markdown_viewer(viewer);
}

static gchar *replace_extension(const gchar *utf8_fn, const gchar *new_ext)
{
gchar *fn_noext, *new_fn, *dot;
fn_noext = g_filename_from_utf8(utf8_fn, -1, NULL, NULL, NULL);
dot = strrchr(fn_noext, '.');
if (dot != NULL) {
*dot = '\0';
}
new_fn = g_strconcat(fn_noext, new_ext, NULL);
g_free(fn_noext);
return new_fn;
}

static void on_export_as_html_activate(GtkMenuItem *item, MarkdownViewer *viewer)
{
GtkWidget *dialog;
GtkFileFilter *filter;
gchar *fn;
GeanyDocument *doc;
gboolean saved = FALSE;

doc = document_get_current();
g_return_if_fail(DOC_VALID(doc));

dialog = gtk_file_chooser_dialog_new(_("Save HTML File As"),
GTK_WINDOW(geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);

fn = replace_extension(DOC_FILENAME(doc), ".html");
if (g_file_test(fn, G_FILE_TEST_EXISTS)) {
/* If the file exists, GtkFileChooser will change to the correct
* directory and show the base name as a suggestion. */
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), fn);
} else {
/* If the file doesn't exist, change the directory and give a suggested
* name for the file, since GtkFileChooser won't do it. */
gchar *dn = g_path_get_dirname(fn);
gchar *bn = g_path_get_basename(fn);
gchar *utf8_name;
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dn);
g_free(dn);
utf8_name = g_filename_to_utf8(bn, -1, NULL, NULL, NULL);
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), utf8_name);
g_free(bn);
g_free(utf8_name);
}
g_free(fn);

filter = gtk_file_filter_new();
gtk_file_filter_set_name(filter, _("HTML Files"));
gtk_file_filter_add_mime_type(filter, "text/html");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);

filter = gtk_file_filter_new();
gtk_file_filter_set_name(filter, _("All Files"));
gtk_file_filter_add_pattern(filter, "*");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);

while (!saved &&
gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
gchar *html = markdown_viewer_get_html(viewer);
GError *error = NULL;
fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
if (! g_file_set_contents(fn, html, -1, &error)) {
dialogs_show_msgbox(GTK_MESSAGE_ERROR,
_("Failed to export Markdown HTML to file '%s': %s"),
fn, error->message);
g_error_free(error);
} else {
saved = TRUE;
}
g_free(fn);
g_free(html);
}

gtk_widget_destroy(dialog);
}
2 changes: 1 addition & 1 deletion markdown/src/viewer.c
Expand Up @@ -309,7 +309,7 @@ on_webview_load_status_notify(WebKitWebView *view, GParamSpec *pspec,
}
}

static gchar *
gchar *
markdown_viewer_get_html(MarkdownViewer *self)
{
gchar *md_as_html, *html = NULL;
Expand Down
1 change: 1 addition & 0 deletions markdown/src/viewer.h
Expand Up @@ -56,6 +56,7 @@ GtkWidget *markdown_viewer_new(MarkdownConfig *conf);
void markdown_viewer_set_markdown(MarkdownViewer *self, const gchar *text,
const gchar *encoding);
void markdown_viewer_queue_update(MarkdownViewer *self);
gchar *markdown_viewer_get_html(MarkdownViewer *self);

G_END_DECLS

Expand Down

0 comments on commit 6e3de19

Please sign in to comment.