From 08287b6508faf5db3acd8a7d8b4b01ed8b897389 Mon Sep 17 00:00:00 2001 From: igor montagner Date: Wed, 30 Sep 2020 21:04:59 -0300 Subject: [PATCH 1/8] Initial version --- .../markdown-actions/markdown-actions.plugin | 10 ++ .../markdown-actions/markdown-actions.vala | 104 ++++++++++++++++++ plugins/markdown-actions/meson.build | 32 ++++++ plugins/meson.build | 1 + 4 files changed, 147 insertions(+) create mode 100644 plugins/markdown-actions/markdown-actions.plugin create mode 100644 plugins/markdown-actions/markdown-actions.vala create mode 100644 plugins/markdown-actions/meson.build diff --git a/plugins/markdown-actions/markdown-actions.plugin b/plugins/markdown-actions/markdown-actions.plugin new file mode 100644 index 0000000000..8ecc83f663 --- /dev/null +++ b/plugins/markdown-actions/markdown-actions.plugin @@ -0,0 +1,10 @@ +[Plugin] +Module=markdown-actions +Loader=C +IAge=2 +Name=Markdown Actions +Description=Adds keyboard shortcuts for quick editing Markdown files +Authors=Igor Montagner +Copyright=Copyright © 2014 Code and Euclide Developers +Website=https://github.com/elementary/code +Hidden=false diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala new file mode 100644 index 0000000000..3deef9de86 --- /dev/null +++ b/plugins/markdown-actions/markdown-actions.vala @@ -0,0 +1,104 @@ +// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- +/*** + BEGIN LICENSE + + Copyright (C) 2013 Madelynn May + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License version 3, as published + by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranties of + MERCHANTABILITY, SATISFACTORY QUALITY, 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, see + + END LICENSE +***/ + +public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable { + Scratch.Widgets.SourceView current_source; + Gtk.SourceSearchContext current_search_context; + + // Consts + // Pneumonoultramicroscopicsilicovolcanoconiosis longest word in a major dictionary @ 45 + private const uint SELECTION_HIGHLIGHT_MAX_CHARS = 45; + + Scratch.Services.Interface plugins; + public Object object { owned get; construct; } + + public void update_state () {} + + public void activate () { + print("ATIVOU!\n"); + plugins = (Scratch.Services.Interface) object; + plugins.hook_document.connect ((doc) => { + if (current_source != null) { + current_source.deselected.disconnect (on_deselection); + current_source.selection_changed.disconnect (on_selection_changed); + } + + current_source = doc.source_view; + current_source.key_press_event.connect((evt) => { + var control = (evt.state & Gdk.ModifierType.CONTROL_MASK) != 0; + if (control) { print("control!!!\n"); } + if (control && evt.keyval == Gdk.Key.b) { + Gtk.TextIter start, end, iter_middle; + current_source.buffer.get_selection_bounds(out start, out end); + + current_source.buffer.insert_at_cursor("****", 4); + + current_source.buffer.get_iter_at_offset(out iter_middle, current_source.buffer.cursor_position - 2); + current_source.buffer.place_cursor(iter_middle); + return true; + } + return false; + }); + + }); + } + + public void on_selection_changed (ref Gtk.TextIter start, ref Gtk.TextIter end) { + if (!start.equal (end)) { + // Expand highlight to current word + if (!start.starts_word ()) { + start.backward_word_start (); + } + + if (!end.ends_word ()) { + end.forward_word_end (); + } + + string selected_text = start.get_buffer ().get_text (start, end, false); + if (selected_text.char_count () > SELECTION_HIGHLIGHT_MAX_CHARS) { + return; + } + + current_search_context = new Gtk.SourceSearchContext ((Gtk.SourceBuffer)current_source.buffer, null); + current_search_context.settings.search_text = selected_text; + current_search_context.set_highlight (true); + } + } + + public void on_deselection () { + if (current_search_context != null) { + current_search_context.settings.search_text = null; + } + } + + public void deactivate () { + if (current_source != null) { + current_source.deselected.disconnect (on_deselection); + current_source.selection_changed.disconnect (on_selection_changed); + } + } +} + +[ModuleInit] +public void peas_register_types (TypeModule module) { + var objmodule = module as Peas.ObjectModule; + objmodule.register_extension_type (typeof (Peas.Activatable), + typeof (Code.Plugins.MarkdownActions)); +} diff --git a/plugins/markdown-actions/meson.build b/plugins/markdown-actions/meson.build new file mode 100644 index 0000000000..d8d15aad3d --- /dev/null +++ b/plugins/markdown-actions/meson.build @@ -0,0 +1,32 @@ +module_name = 'markdown-actions' + +module_files = [ + 'markdown-actions.vala', +] + +module_deps = [ + codecore_dep, +] + +shared_module( + module_name, + module_files, + dependencies: module_deps, + install: true, + install_dir: join_paths(pluginsdir, module_name), +) + +custom_target(module_name + '.plugin_merge', + input: module_name + '.plugin', + output: module_name + '.plugin', + command : [msgfmt, + '--desktop', + '--keyword=Description', + '--keyword=Name', + '-d' + join_paths(meson.source_root (), 'po', 'plugins'), + '--template=@INPUT@', + '-o@OUTPUT@', + ], + install : true, + install_dir: join_paths(pluginsdir, module_name), +) diff --git a/plugins/meson.build b/plugins/meson.build index fe067a9ac8..2e8855ee1d 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -4,6 +4,7 @@ subdir('brackets-completion') subdir('detect-indent') subdir('editorconfig') subdir('highlight-word-selection') +subdir('markdown-actions') subdir('outline') subdir('pastebin') subdir('preserve-indent') From 07306dcd367690d95512042b020fc7db51ed637d Mon Sep 17 00:00:00 2001 From: igor montagner Date: Thu, 1 Oct 2020 21:43:19 -0300 Subject: [PATCH 2/8] Italic and link implemented. --- .../markdown-actions/markdown-actions.vala | 109 +++++++++++------- 1 file changed, 67 insertions(+), 42 deletions(-) diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala index 3deef9de86..40ffce4ea2 100644 --- a/plugins/markdown-actions/markdown-actions.vala +++ b/plugins/markdown-actions/markdown-actions.vala @@ -32,66 +32,91 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable public void update_state () {} public void activate () { - print("ATIVOU!\n"); plugins = (Scratch.Services.Interface) object; plugins.hook_document.connect ((doc) => { if (current_source != null) { - current_source.deselected.disconnect (on_deselection); - current_source.selection_changed.disconnect (on_selection_changed); + current_source.key_press_event.disconnect (shortcut_handler); } - + current_source = doc.source_view; - current_source.key_press_event.connect((evt) => { - var control = (evt.state & Gdk.ModifierType.CONTROL_MASK) != 0; - if (control) { print("control!!!\n"); } - if (control && evt.keyval == Gdk.Key.b) { - Gtk.TextIter start, end, iter_middle; - current_source.buffer.get_selection_bounds(out start, out end); - - current_source.buffer.insert_at_cursor("****", 4); - - current_source.buffer.get_iter_at_offset(out iter_middle, current_source.buffer.cursor_position - 2); - current_source.buffer.place_cursor(iter_middle); - return true; - } - return false; - }); - + configure_shortcuts (); + + current_source.notify["language"].connect (configure_shortcuts); }); } - public void on_selection_changed (ref Gtk.TextIter start, ref Gtk.TextIter end) { - if (!start.equal (end)) { - // Expand highlight to current word - if (!start.starts_word ()) { - start.backward_word_start (); - } - - if (!end.ends_word ()) { - end.forward_word_end (); - } + private void configure_shortcuts () { + var lang = current_source.language; + if (lang != null && lang.id == "markdown") { + current_source.key_press_event.connect (shortcut_handler); + } else { + current_source.key_press_event.disconnect (shortcut_handler); + } + } - string selected_text = start.get_buffer ().get_text (start, end, false); - if (selected_text.char_count () > SELECTION_HIGHLIGHT_MAX_CHARS) { - return; - } + private bool shortcut_handler (Gdk.EventKey evt) { + var control = (evt.state & Gdk.ModifierType.CONTROL_MASK) != 0; + var shift = (evt.state & Gdk.ModifierType.SHIFT_MASK) != 0; + if (control && !shift && evt.keyval == Gdk.Key.b) { + add_markdown_tag ("**"); + return true; + } else if (control && shift && evt.keyval == Gdk.Key.I) { + add_markdown_tag ("_"); + return true; + } else if (control && evt.keyval == Gdk.Key.k) { + insert_link (); + } + return false; + } - current_search_context = new Gtk.SourceSearchContext ((Gtk.SourceBuffer)current_source.buffer, null); - current_search_context.settings.search_text = selected_text; - current_search_context.set_highlight (true); + private void insert_link () { + var current_buffer = current_source.buffer; + if (current_buffer.has_selection) { + insert_around_selection ("[", "]"); + current_buffer.insert_at_cursor ("()", 2); + go_back_n_chars (1); + } else { + current_buffer.insert_at_cursor ("[]", 2); + current_buffer.insert_at_cursor ("()", 2); + go_back_n_chars (3); } } - public void on_deselection () { - if (current_search_context != null) { - current_search_context.settings.search_text = null; + private void go_back_n_chars (int back_chars) { + Gtk.TextIter insert_position; + var current_buffer = current_source.buffer; + current_buffer.get_iter_at_offset (out insert_position, current_buffer.cursor_position - back_chars); + current_buffer.place_cursor (insert_position); + } + + private void insert_around_selection (string before, string after) { + Gtk.TextIter start, end; + var current_buffer = current_source.buffer; + current_buffer.get_selection_bounds (out start, out end); + var mark_end = new Gtk.TextMark (null); + current_buffer.add_mark (mark_end, end); + current_buffer.place_cursor (start); + current_buffer.insert_at_cursor (before, before.length); + + current_buffer.get_iter_at_mark (out end, mark_end); + current_buffer.place_cursor (end); + current_buffer.insert_at_cursor (after, after.length); + } + + public void add_markdown_tag (string tag) { + var current_buffer = current_source.buffer; + if (current_buffer.has_selection) { + insert_around_selection (tag, tag); + } else { + current_buffer.insert_at_cursor (tag, tag.length); + current_buffer.insert_at_cursor (tag, tag.length); } + go_back_n_chars (tag.length); } public void deactivate () { if (current_source != null) { - current_source.deselected.disconnect (on_deselection); - current_source.selection_changed.disconnect (on_selection_changed); + current_source.key_press_event.disconnect (shortcut_handler); } } } From ffe7e3ecb2ed38c6013498f2b6fe37f3f61d862e Mon Sep 17 00:00:00 2001 From: igor montagner Date: Thu, 1 Oct 2020 21:50:38 -0300 Subject: [PATCH 3/8] Add icon. --- plugins/markdown-actions/markdown-actions.plugin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/markdown-actions/markdown-actions.plugin b/plugins/markdown-actions/markdown-actions.plugin index 8ecc83f663..937ca8e69b 100644 --- a/plugins/markdown-actions/markdown-actions.plugin +++ b/plugins/markdown-actions/markdown-actions.plugin @@ -4,7 +4,7 @@ Loader=C IAge=2 Name=Markdown Actions Description=Adds keyboard shortcuts for quick editing Markdown files +Icon=format-text-bold Authors=Igor Montagner -Copyright=Copyright © 2014 Code and Euclide Developers -Website=https://github.com/elementary/code +Copyright=Copyright © 2020 Igor Montagner Hidden=false From 1daff51359b305c39f34f8d2b2bd1aa68c571531 Mon Sep 17 00:00:00 2001 From: igor montagner Date: Thu, 1 Oct 2020 21:56:58 -0300 Subject: [PATCH 4/8] Minor fixes. --- plugins/markdown-actions/markdown-actions.vala | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala index 40ffce4ea2..547904cfa4 100644 --- a/plugins/markdown-actions/markdown-actions.vala +++ b/plugins/markdown-actions/markdown-actions.vala @@ -2,7 +2,7 @@ /*** BEGIN LICENSE - Copyright (C) 2013 Madelynn May + Copyright (C) 2020 Igor Montagner This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, as published by the Free Software Foundation. @@ -20,13 +20,8 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable { Scratch.Widgets.SourceView current_source; - Gtk.SourceSearchContext current_search_context; - - // Consts - // Pneumonoultramicroscopicsilicovolcanoconiosis longest word in a major dictionary @ 45 - private const uint SELECTION_HIGHLIGHT_MAX_CHARS = 45; - Scratch.Services.Interface plugins; + public Object object { owned get; construct; } public void update_state () {} @@ -37,7 +32,7 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable if (current_source != null) { current_source.key_press_event.disconnect (shortcut_handler); } - + current_source = doc.source_view; configure_shortcuts (); From 16cecc98b9f6919368319e607fa2923476a5f2d4 Mon Sep 17 00:00:00 2001 From: igor montagner Date: Sat, 24 Oct 2020 09:33:04 -0300 Subject: [PATCH 5/8] Disconnect notify["language"] as well. --- plugins/markdown-actions/markdown-actions.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala index 547904cfa4..458b1da35e 100644 --- a/plugins/markdown-actions/markdown-actions.vala +++ b/plugins/markdown-actions/markdown-actions.vala @@ -31,6 +31,7 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable plugins.hook_document.connect ((doc) => { if (current_source != null) { current_source.key_press_event.disconnect (shortcut_handler); + current_source.notify["language"].disconnect (configure_shortcuts); } current_source = doc.source_view; @@ -112,6 +113,7 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable public void deactivate () { if (current_source != null) { current_source.key_press_event.disconnect (shortcut_handler); + current_source.notify["language"].disconnect (configure_shortcuts); } } } From 8db90f35609fa0abf5762d4542b0bdbf9fa6095f Mon Sep 17 00:00:00 2001 From: igor montagner Date: Sat, 24 Oct 2020 10:08:44 -0300 Subject: [PATCH 6/8] Add switch statement and check for other mod keys. --- .../markdown-actions/markdown-actions.vala | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala index 458b1da35e..4015d055fb 100644 --- a/plugins/markdown-actions/markdown-actions.vala +++ b/plugins/markdown-actions/markdown-actions.vala @@ -53,15 +53,28 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable private bool shortcut_handler (Gdk.EventKey evt) { var control = (evt.state & Gdk.ModifierType.CONTROL_MASK) != 0; var shift = (evt.state & Gdk.ModifierType.SHIFT_MASK) != 0; - if (control && !shift && evt.keyval == Gdk.Key.b) { - add_markdown_tag ("**"); - return true; - } else if (control && shift && evt.keyval == Gdk.Key.I) { - add_markdown_tag ("_"); - return true; - } else if (control && evt.keyval == Gdk.Key.k) { - insert_link (); + var other_mods = (evt.state & Gtk.accelerator_get_default_mod_mask () & + ~Gdk.ModifierType.SHIFT_MASK & + ~Gdk.ModifierType.CONTROL_MASK) != 0; + + if (evt.is_modifier == 1 || other_mods == true) { + return false; } + + if (control && shift) { + switch (evt.keyval) { + case Gdk.Key.B: + add_markdown_tag ("**"); + return true; + case Gdk.Key.I: + add_markdown_tag ("_"); + return true; + case Gdk.Key.K: + insert_link (); + break; + } + } + return false; } From 779fe52fdb2c7d81040edd97cf1058a951e80cdd Mon Sep 17 00:00:00 2001 From: Igor Montagner Date: Mon, 26 Oct 2020 14:25:47 -0300 Subject: [PATCH 7/8] Edit appdata. --- data/io.elementary.code.appdata.xml.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/io.elementary.code.appdata.xml.in b/data/io.elementary.code.appdata.xml.in index 02d66e19fb..5c5d15e891 100644 --- a/data/io.elementary.code.appdata.xml.in +++ b/data/io.elementary.code.appdata.xml.in @@ -48,6 +48,10 @@ +

New features:

+
    +
  • New Markdown plugin for WYSIWYG-like editing.
  • +

Minor updates:

  • Allow Spell Checker extension in Markdown files
  • From 497e71db806d0f92e0c8d699bd7b571873b629bf Mon Sep 17 00:00:00 2001 From: igor montagner Date: Sat, 28 Nov 2020 08:34:56 -0300 Subject: [PATCH 8/8] Include all text inclusions as one user action. --- plugins/markdown-actions/markdown-actions.vala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala index 4015d055fb..ce003c40df 100644 --- a/plugins/markdown-actions/markdown-actions.vala +++ b/plugins/markdown-actions/markdown-actions.vala @@ -80,6 +80,7 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable private void insert_link () { var current_buffer = current_source.buffer; + current_buffer.begin_user_action (); if (current_buffer.has_selection) { insert_around_selection ("[", "]"); current_buffer.insert_at_cursor ("()", 2); @@ -89,6 +90,7 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable current_buffer.insert_at_cursor ("()", 2); go_back_n_chars (3); } + current_buffer.end_user_action (); } private void go_back_n_chars (int back_chars) { @@ -114,12 +116,14 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable public void add_markdown_tag (string tag) { var current_buffer = current_source.buffer; + current_buffer.begin_user_action (); if (current_buffer.has_selection) { insert_around_selection (tag, tag); } else { current_buffer.insert_at_cursor (tag, tag.length); current_buffer.insert_at_cursor (tag, tag.length); } + current_buffer.end_user_action (); go_back_n_chars (tag.length); }