From ea2fccfaca1a369be8d7945368aa9c3eefbcc891 Mon Sep 17 00:00:00 2001 From: "Romain F. T" Date: Sat, 8 Feb 2020 18:49:34 +0100 Subject: [PATCH] Handle cases where there is no CSS as pointed out by #19, this wasn't clear at all. But now: - the switch for css (correctly used by the export) has an effect on the preview if (un)activated from the prefs - no more attempts to add html/head/body twice on html documents - use pandoc options for "standalone" files with CSS instead of manually adding needed tags --- README.md | 21 ++- markdown_preview/export.py | 67 ++++---- markdown_preview/preview.py | 143 ++++++++++-------- ...gedit.plugins.markdown_preview.gschema.xml | 5 + 4 files changed, 143 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index b53d929..60d26fb 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,26 @@ -This is a plugin for the Gedit text editor, previewing .md files in the side (`F9`) or the bottom (`Ctrl+F9`) panel. +This is a plugin for the Gedit text editor, previewing .md files in the side (`F9`) or the bottom (`Ctrl+F9`) pane. @@ -28,7 +37,7 @@ This is a plugin for the Gedit text editor, previewing .md files in the side (`F - or export to HTML with `python3-markdown` and its [extensions](https://python-markdown.github.io/extensions/) - Edition assistance: - insert an image in your file - - insert markdown tags in your text with keyboard shortcuts + - insert markdown tags in your text with right-click menu or keyboard shortcuts ---- diff --git a/markdown_preview/export.py b/markdown_preview/export.py index 729da02..5d299bd 100644 --- a/markdown_preview/export.py +++ b/markdown_preview/export.py @@ -35,6 +35,8 @@ except: _ = lambda s: s +################################################################################ + P3MD_PLUGINS = { 'extra': "Extras", 'toc': _("Table of content"), @@ -78,13 +80,13 @@ 'plain': _("plain text (.txt)"), 'pptx': _("PowerPoint slideshow (.pptx)"), 'rtf': _("Rich Text Format (.rtf)"), - 'revealjs': _("reveal.js slideshow (HTML with Javascript)"), + 'revealjs': _("reveal.js slideshow (HTML/JS)"), 'custom': _("Custom command line") } PANDOC_FORMATS_PREVIEW = { 'html5': _("HTML5"), - 'revealjs': _("reveal.js slideshow (HTML with Javascript)"), + 'revealjs': _("reveal.js slideshow (HTML/JS)"), 'custom': _("Custom command line") } @@ -99,25 +101,34 @@ def __init__(self, settings, related_window, parent_widget): builder = Gtk.Builder().new_from_file(BASE_PATH + '/css_box.ui') self.full_widget = builder.get_object('css_box') - self.switch_css = builder.get_object('switch_css') - self.switch_css.connect('notify::active', self.on_css_changed) - self.css_sensitive_box = builder.get_object('css_sensitive_box') - file_chooser_btn_css = builder.get_object('file_chooser_btn_css') - file_chooser_btn_css.connect('clicked', self.on_choose_css) + file_chooser_btn_css.connect('clicked', self._on_choose_css) self.style_label = builder.get_object('style_label') self.css_uri = self._settings.get_string('style') - self.update_file_chooser_btn_label() - def on_css_changed(self, w, a): - self.css_sensitive_box.set_sensitive(w.get_state()) - self.parent_widget.update_css(self.css_uri) + self.switch_css = builder.get_object('switch_css') + css_is_active = self._settings.get_boolean('use-style') + self.switch_css.set_active(css_is_active) + self.switch_css.connect('notify::active', self._on_use_css_changed) + self.css_sensitive_box = builder.get_object('css_sensitive_box') + + self._set_css_active(css_is_active) + self._update_file_chooser_btn_label() + + def _set_css_active(self, css_is_active): + self.css_sensitive_box.set_sensitive(css_is_active) + + def _on_use_css_changed(self, *args): + css_is_active = args[0].get_state() + self._set_css_active(css_is_active) + self.parent_widget.update_css(css_is_active, self.css_uri) - def on_choose_css(self, w): + def _on_choose_css(self, *args): # Building a FileChooserDialog for the CSS file file_chooser = Gtk.FileChooserNative.new(_("Select a CSS file"), \ - self.related_window, Gtk.FileChooserAction.OPEN, \ - _("Select"), _("Cancel")) + self.related_window, + Gtk.FileChooserAction.OPEN, \ + _("Select"), _("Cancel")) onlyCSS = Gtk.FileFilter() onlyCSS.set_name(_("Stylesheet")) onlyCSS.add_mime_type('text/css') @@ -126,14 +137,16 @@ def on_choose_css(self, w): if response == Gtk.ResponseType.ACCEPT: self.css_uri = file_chooser.get_uri() - self.update_file_chooser_btn_label() - self.parent_widget.update_css(self.css_uri) + self._update_file_chooser_btn_label() + self.parent_widget.update_css(self.switch_css.get_active(), self.css_uri) file_chooser.destroy() - def update_file_chooser_btn_label(self): + def _update_file_chooser_btn_label(self): label = self.css_uri - if len(label) > 50: - label = '…' + label[-50:] + if label == '': + label = _("Select a CSS file") + if len(label) > 45: + label = '…' + label[-45:] self.style_label.set_label(label) ############################################################################ @@ -296,7 +309,7 @@ def do_cancel_export(self): ############################################################################ - def update_css(self, uri): + def update_css(self, is_active, uri): self.on_pandoc_format_changed(self._backend.format_combobox) def on_pandoc_format_changed(self, w): @@ -378,6 +391,7 @@ def export_p3md(self): start, end = doc.get_bounds() unsaved_text = doc.get_text(start, end, True) content = markdown.markdown(unsaved_text, extensions=md_extensions) + # FIXME code complètement con ci-après with open(file_chooser.get_filename(), 'w') as f: f.write(content) if self.css_manager.switch_css.get_active(): @@ -417,15 +431,15 @@ class MdConfigWidget(Gtk.Box): __gtype_name__ = 'MdConfigWidget' def __init__(self, datadir, **kwargs): - super().__init__(**kwargs, orientation=Gtk.Orientation.VERTICAL, \ - spacing=10, margin=10) - # XXX what's datadir ?? + super().__init__(**kwargs, orientation=Gtk.Orientation.HORIZONTAL) + # print(datadir) # TODO c'est le path de là où est le plugin, ça peut + # aider à mettre un css par défaut ? self._settings = Gio.Settings.new(MD_PREVIEW_KEY_BASE) builder = Gtk.Builder().new_from_file(BASE_PATH + '/prefs.ui') # builder.set_translation_domain('gedit-plugin-markdown-preview') # TODO stack = builder.get_object('stack') - switcher = Gtk.StackSwitcher(stack=stack, halign=Gtk.Align.CENTER) + sidebar = Gtk.StackSidebar(stack=stack) ### PREVIEW PAGE ####################################################### @@ -469,7 +483,7 @@ def __init__(self, datadir, **kwargs): # https://github.com/GNOME/gtk/blob/master/gdk/keynames.txt for i in range(len(SETTINGS_KEYS)): self.add_keybinding(SETTINGS_KEYS[i], LABELS[i]) - self.add(switcher) + self.add(sidebar) self.add(stack) ############################################################################ @@ -509,7 +523,8 @@ def on_position_changed(self, w): def on_auto_manage_changed(self, w, a): self._settings.set_boolean('auto-manage-panel', w.get_state()) - def update_css(self, uri): + def update_css(self, is_active, uri): + self._settings.set_boolean('use-style', is_active) self._settings.set_string('style', uri) self.on_pandoc_format_changed(self._backend.format_combobox) diff --git a/markdown_preview/preview.py b/markdown_preview/preview.py index 5b90597..51d774c 100644 --- a/markdown_preview/preview.py +++ b/markdown_preview/preview.py @@ -89,10 +89,14 @@ def do_deactivate(self): self._webview.disconnect(self._handlers[2]) self._settings.disconnect(self._handlers[1]) self._settings.disconnect(self._handlers[0]) - self.delete_temp_file() + self._delete_temp_file() self.remove_from_panel() self.preview_bar.destroy() + def _delete_temp_file(self): + if self.temp_file_md.query_exists(): + self.temp_file_md.delete() + ############################################################################ # Misc ##################################################################### @@ -264,36 +268,7 @@ def on_next_page(self, *args): self.on_reload() ############################################################################ - - def delete_temp_file(self): - if self.temp_file_md.query_exists(): - self.temp_file_md.delete() - - def on_file_changed(self, *args): - self.file_format = self.recognize_format() - self.update_visibility() - if self.file_format != 'error': - self.on_reload() - - def recognize_format(self): - doc = self.parent_plugin.window.get_active_document() - # It will not load documents which are not .md/.html/.tex - name = doc.get_short_name_for_display() - temp = name.split('.')[-1] - if temp == 'md': - self.close_warning() - return 'md' - elif temp == 'html': - self.close_warning() - return 'html' - elif temp == 'tex': - self.close_warning() - return 'tex' - if doc.is_untitled(): - self.display_warning(_("Can't preview an unsaved document")) # FIXME - else: - self.display_warning(_("Unsupported type of document: ") + name) - return 'error' + # Reload ################################################################### def on_reload(self, *args): # Guard clause: it will not load documents which are not supported @@ -305,6 +280,10 @@ def on_reload(self, *args): if self.parent_plugin._auto_position: self.auto_change_panel() + css_uri = '' + if self._settings.get_boolean('use-style'): + css_uri = self._settings.get_string('style') + html_content = '' doc = self.parent_plugin.window.get_active_document() start, end = doc.get_bounds() @@ -312,12 +291,12 @@ def on_reload(self, *args): if self.file_format == 'html': html_content = self.get_html_from_html(unsaved_text) elif self.file_format == 'tex': - html_content = self.get_html_from_tex() + html_content = self.get_html_from_tex(css_uri) elif self.file_format == 'md': if self._settings.get_string('backend') == 'python': - html_content = self.get_html_from_md_python(unsaved_text) + html_content = self.get_html_from_md_python(unsaved_text, css_uri) else: - html_content = self.get_html_from_md_pandoc(unsaved_text) + html_content = self.get_html_from_md_pandoc(unsaved_text, css_uri) else: return @@ -331,28 +310,23 @@ def on_reload(self, *args): self._webview.load_bytes(bytes_content, 'text/html', 'UTF-8', dummy_uri) def get_html_from_html(self, unsaved_text): - # FIXME is bad idea if the document already has these tags - pre_string = '' - post_string = '' - unsaved_text = self.current_page(unsaved_text, HTML_SPLITTERS) - html_content = pre_string + unsaved_text + post_string - return html_content - - def get_html_from_tex(self): + # CSS not applied if it's HTML + return self.current_page(unsaved_text, HTML_SPLITTERS) + + def get_html_from_tex(self, css_uri): doc = self.parent_plugin.window.get_active_document() file_path = doc.get_location().get_path() + # TODO FIXME splitters ? # It uses pandoc to produce the html code - pre_string = '' - post_string = '' - result = subprocess.run(['pandoc', file_path], stdout=subprocess.PIPE) - html_string = result.stdout.decode('utf-8') - html_string = self.current_page(html_string, HTML_SPLITTERS) - html_content = pre_string + html_string + post_string + command = ['pandoc', '-s', file_path, '--metadata', 'pagetitle=Preview'] + if css_uri != '': + command = command + ['-c', css_uri] + result = subprocess.run(command, stdout=subprocess.PIPE) + html_content = result.stdout.decode('utf-8') return html_content - def get_html_from_md_pandoc(self, unsaved_text): + def get_html_from_md_pandoc(self, unsaved_text, css_uri): # Get the current document, or the temporary document if requested unsaved_text = self.current_page(unsaved_text, MARKDOWN_SPLITTERS) f = open(BASE_TEMP_NAME + '.md', 'w') @@ -361,25 +335,72 @@ def get_html_from_md_pandoc(self, unsaved_text): file_path = self.temp_file_md.get_path() # It uses pandoc to produce the html code - pre_string = '' - post_string = '' - result = subprocess.run(['pandoc', file_path], stdout=subprocess.PIPE) - html_string = result.stdout.decode('utf-8') - html_content = pre_string + html_string + post_string # TODO pandoc can have CSS without hacks + command = ['pandoc', '-s', file_path, '--metadata', 'pagetitle=Preview'] + if css_uri != '': + command = command + ['-c', css_uri] + result = subprocess.run(command, stdout=subprocess.PIPE) + html_content = result.stdout.decode('utf-8') return html_content - def get_html_from_md_python(self, unsaved_text): + def get_revealjs_from_md(self, unsaved_text): + # Get the current document, or the temporary document if requested + unsaved_text = self.current_page(unsaved_text, MARKDOWN_SPLITTERS) + f = open(BASE_TEMP_NAME + '.md', 'w') + f.write(unsaved_text) + f.close() + file_path = self.temp_file_md.get_path() + + # It uses pandoc to produce the html code + # command = ['pandoc', '-s', file_path, '--metadata', 'pagetitle=Preview', \ + # '-t', 'revealjs', '-V', 'revealjs-url=http://lab.hakim.se/reveal-js'] + # if css_uri != '': + # command = command + ['-c', css_uri] + # result = subprocess.run(command, stdout=subprocess.PIPE) + # html_content = result.stdout.decode('utf-8') + # return html_content # TODO + + def get_html_from_md_python(self, unsaved_text, css_uri): unsaved_text = self.current_page(unsaved_text, MARKDOWN_SPLITTERS) - # TODO https://github.com/Python-Markdown/markdown/wiki/Third-Party-Extensions + # https://github.com/Python-Markdown/markdown/wiki/Third-Party-Extensions md_extensions = self._settings.get_strv('extensions') - pre_string = '' + if css_uri == '': + pre_string = '' + else: + pre_string = '' + \ + '' post_string = '' html_string = markdown.markdown(unsaved_text, extensions=md_extensions) html_content = pre_string + html_string + post_string return html_content + ############################################################################ + + def on_file_changed(self, *args): + self.file_format = self.recognize_format() + self.update_visibility() + if self.file_format != 'error': + self.on_reload() + + def recognize_format(self): + doc = self.parent_plugin.window.get_active_document() + # It will not load documents which are not .md/.html/.tex + name = doc.get_short_name_for_display() + temp = name.split('.')[-1] + if temp == 'md': + self.close_warning() + return 'md' + elif temp == 'html': + self.close_warning() + return 'html' + elif temp == 'tex': + self.close_warning() + return 'tex' + if doc.is_untitled(): + self.display_warning(_("Can't preview an unsaved document")) # FIXME + else: + self.display_warning(_("Unsupported type of document: ") + name) + return 'error' + def current_page(self, lang_string, splitters_array): if self.pagination_mode == 'whole': return lang_string @@ -391,7 +412,7 @@ def current_page(self, lang_string, splitters_array): correct_splitter = splitters_array[0] # The document is (as much as possible) splitted in its original - # language. It avoid converting markdown to html which wouldn't be + # language. It avoids converting some markdown to html which wouldn't be # rendered anyway. lang_pages = lang_string.split(correct_splitter) self.page_number = len(lang_pages) diff --git a/org.gnome.gedit.plugins.markdown_preview.gschema.xml b/org.gnome.gedit.plugins.markdown_preview.gschema.xml index c6db67c..b855db9 100644 --- a/org.gnome.gedit.plugins.markdown_preview.gschema.xml +++ b/org.gnome.gedit.plugins.markdown_preview.gschema.xml @@ -32,6 +32,11 @@ Custom export command + + false + Use a stylesheet + + "" Stylesheet URI