From 845553a4306eed86af07af3bd3e14799a519edc6 Mon Sep 17 00:00:00 2001 From: Ali Ayas Date: Mon, 30 Nov 2015 02:37:11 +0200 Subject: [PATCH 01/23] Init v2.1.5 branch --- messages.json | 3 ++- messages/2.1.5.md | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 messages/2.1.5.md diff --git a/messages.json b/messages.json index 34cdf3fc..e1f466f9 100644 --- a/messages.json +++ b/messages.json @@ -14,5 +14,6 @@ "2.1.1": "messages/2.1.1.md", "2.1.2": "messages/2.1.2.md", "2.1.3": "messages/2.1.3.md", - "2.1.4": "messages/2.1.4.md" + "2.1.4": "messages/2.1.4.md", + "2.1.5": "messages/2.1.5.md" } diff --git a/messages/2.1.5.md b/messages/2.1.5.md new file mode 100644 index 00000000..c7c5b0a8 --- /dev/null +++ b/messages/2.1.5.md @@ -0,0 +1,12 @@ +# MarkdownEditing 2.1.5 Changelog + +Your _MarkdownEditing_ plugin is updated. Enjoy new version. For any type of +feedback you can use [GitHub issues][issues]. + +## Bug Fixes + +## New Features + +## Changes + +[issues]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues From 495d1fc2e6ea9374846c9205c49c0588cea61de4 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 16 Dec 2015 13:36:33 +0800 Subject: [PATCH 02/23] port insert_refereces to ST3 and change paste_as_reference related #311 --- insert_references.py | 118 ++++++++++++++++++++---------------------- messages/2.1.5.md | 16 ++++++ paste_as_reference.py | 43 ++++++++++++++- 3 files changed, 115 insertions(+), 62 deletions(-) create mode 100644 messages/2.1.5.md diff --git a/insert_references.py b/insert_references.py index c75d2b2d..cc78cfd4 100644 --- a/insert_references.py +++ b/insert_references.py @@ -26,39 +26,47 @@ def check_for_link(view, url): view.find_all(r'^\s{0,3}\[([^^\]]+)\]:[ \t]+' + re.escape(url) + '$', 0, '$1', titles) return titles[0] if titles else None - -def append_reference_link(edit, view, title, url): - # Detect if file ends with \n - if view.substr(view.size() - 1) == '\n': - nl = '' - else: - nl = '\n' - # Append the new reference link to the end of the file - view.insert(edit, view.size(), '{0}[{1}]: {2}\n'.format(nl, title, url)) - - -def insert_references(edit, view, title): - # Add a reference with given title at the current cursor or around the current selection(s) - sels = view.sel() - caret = [] - - for sel in sels: - text = view.substr(sel) - # If something is selected... - if len(text) > 0: - # ... turn the selected text into the link text - view.replace(edit, sel, "[{0}][{1}]".format(text, title)) +class AppendReferenceLinkCommand(sublime_plugin.TextCommand): + def run(self, edit, title, url): + view = self.view + # Detect if file ends with \n + if view.substr(view.size() - 1) == '\n': + nl = '' else: - # Add the link, with empty link text, and the caret positioned - # ready to type the link text - view.replace(edit, sel, "[][{0}]".format(title)) - caret += [sublime.Region(sel.begin() + 1, sel.begin() + 1)] - - if len(caret) > 0: - sels.clear() - for c in caret: - sels.add(c) - + nl = '\n' + # Append the new reference link to the end of the file + view.insert(edit, view.size(), '{0}[{1}]: {2}\n'.format(nl, title, url)) + InsertReferencesCommand.run(self, edit, title) + +def append_reference_link(view, title, url): + view.run_command("append_reference_link", {"title": title, "url": url}) + +class InsertReferencesCommand(sublime_plugin.TextCommand): + def run(self, edit, title): + view = self.view + # Add a reference with given title at the current cursor or around the current selection(s) + sels = view.sel() + caret = [] + + for sel in sels: + text = view.substr(sel) + # If something is selected... + if len(text) > 0: + # ... turn the selected text into the link text + view.replace(edit, sel, "[{0}][{1}]".format(text, title)) + else: + # Add the link, with empty link text, and the caret positioned + # ready to type the link text + view.replace(edit, sel, "[][{0}]".format(title)) + caret += [sublime.Region(sel.begin() + 1, sel.begin() + 1)] + + if len(caret) > 0: + sels.clear() + for c in caret: + sels.add(c) + +def insert_references(view, title): + view.run_command("insert_references", {"title": title}) # Inspired by http://www.leancrew.com/all-this/2012/08/markdown-reference-links-in-bbedit/ # Appends a new reference link to end of document, using a user-input name and URL. @@ -100,16 +108,10 @@ def insert_link(self, linkurl, newref, actually_insert=True): None, None) return - edit = self.view.begin_edit() - - try: - if actually_insert: - append_reference_link(edit, self.view, newref, linkurl) - - insert_references(edit, self.view, newref) - - finally: - self.view.end_edit(edit) + if actually_insert: + append_reference_link(self.view, newref, linkurl) + else: + insert_references(self.view, newref) def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) @@ -132,25 +134,19 @@ def run(self, edit): None, None) def insert_link(self, linkurl): - edit = self.view.begin_edit() - - try: - linkurl = mangle_url(linkurl) - newref = check_for_link(self.view, linkurl) - if not newref: - # Find the next reference number - reflinks = self.view.find_all(r'(?<=^\[)(\d+)(?=\]: )') - if len(reflinks) == 0: - newref = 1 - else: - newref = max(int(self.view.substr(reg)) for reg in reflinks) + 1 - - append_reference_link(edit, self.view, newref, linkurl) - - insert_references(edit, self.view, newref) - - finally: - self.view.end_edit(edit) + linkurl = mangle_url(linkurl) + newref = check_for_link(self.view, linkurl) + if not newref: + # Find the next reference number + reflinks = self.view.find_all(r'(?<=^\[)(\d+)(?=\]: )') + if len(reflinks) == 0: + newref = 1 + else: + newref = max(int(self.view.substr(reg)) for reg in reflinks) + 1 + + append_reference_link(self.view, newref, linkurl) + else: + insert_references(self.view, newref) def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) diff --git a/messages/2.1.5.md b/messages/2.1.5.md new file mode 100644 index 00000000..ccf4c72a --- /dev/null +++ b/messages/2.1.5.md @@ -0,0 +1,16 @@ +# MarkdownEditing 2.1.5 Changelog + +Your _MarkdownEditing_ plugin is updated. Enjoy new version. For any type of +feedback you can use [GitHub issues][issues]. + +## Bug Fixes + +* "Insert References" commands get fixed. Select something and press `alt+ctrl+r` to try `insert_named_reference` command, and `super+ctrl+shift+r` to try `insert_numbered_reference`. + +## New Features + +## Changes + +* "Paste As Reference" works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. + +[issues]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues diff --git a/paste_as_reference.py b/paste_as_reference.py index 468f1cca..a39d565e 100644 --- a/paste_as_reference.py +++ b/paste_as_reference.py @@ -1,6 +1,33 @@ import sublime import sublime_plugin +import re +def append_reference_link(edit, view, title, url): + # Detect if file ends with \n + if view.substr(view.size() - 1) == '\n': + nl = '' + else: + nl = '\n' + # Append the new reference link to the end of the file + edit_position = view.size() + len(nl) + 1 + view.insert(edit, view.size(), '{0}[{1}]: {2}\n'.format(nl, title, url)) + return sublime.Region(edit_position, edit_position + len(title)) + +def suggest_default_link_name(title): + # Camel case impl. + ret = '' + for word in title.split(): + ret += word.capitalize() + if len(ret) > 30: + break + return 'link' + ret + +def is_url(contents): + # If the clipboard contains an URL, return it + # Otherwise, return an empty string + re_match_urls = re.compile(r"""((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.‌​][a-z]{2,4}/)(?:[^\s()<>]+|(([^\s()<>]+|(([^\s()<>]+)))*))+(?:(([^\s()<>]+|(‌​([^\s()<>]+)))*)|[^\s`!()[]{};:'".,<>?«»“”‘’]))""", re.DOTALL) + m = re_match_urls.search(contents) + return True if m else False class PasteAsReferenceCommand(sublime_plugin.TextCommand): def run(self, edit): @@ -8,7 +35,21 @@ def run(self, edit): sel = view.sel()[0] text = view.substr(sel) contents = sublime.get_clipboard() - self.view.replace(edit, sel, "["+text+"]: "+contents) + if is_url(contents): + suggested_title = suggest_default_link_name(text) + link = contents + else: + suggested_title = suggest_default_link_name(contents) + link = '' + + edit_position = sel.end() + 3 + self.view.replace(edit, sel, "[" + text + "][" + suggested_title + "]") + reference_region = append_reference_link(edit, view, suggested_title, link) + sel = view.sel() + sel.clear() + sel.add(sublime.Region(edit_position, edit_position + len(suggested_title))) + sel.add(reference_region) + def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) From f0811e7ca71bb19ab60bc950d8e58af33be1e787 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 16 Dec 2015 14:12:33 +0800 Subject: [PATCH 03/23] add four link paste to command pallete --- Default.sublime-commands | 16 ++++++++++++++++ messages/2.1.5.md | 2 ++ 2 files changed, 18 insertions(+) diff --git a/Default.sublime-commands b/Default.sublime-commands index 4144b655..dcd52dea 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -32,5 +32,21 @@ { "caption": "MarkdownEditing: Switch List Bullet Type", "command": "switch_list_bullet_type" + }, + { + "caption": "MarkdownEditing: Paste as Link", + "command": "paste_as_link" + }, + { + "caption": "MarkdownEditing: Paste as Reference", + "command": "paste_as_reference" + }, + { + "caption": "MarkdownEditing: Insert Named Reference...", + "command": "insert_named_reference" + }, + { + "caption": "MarkdownEditing: Insert Numbered Reference...", + "command": "insert_numbered_reference" } ] diff --git a/messages/2.1.5.md b/messages/2.1.5.md index ccf4c72a..b1c4afb7 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -9,6 +9,8 @@ feedback you can use [GitHub issues][issues]. ## New Features +* Four new commands added to command pallete (Paste as Link, Paste as Reference, Insert Named Reference, Insert Numbered Reference) + ## Changes * "Paste As Reference" works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. From 2299919cb6dd0511e6d4dc7c1dd0c2ce5c00aa77 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 16 Dec 2015 14:57:58 +0800 Subject: [PATCH 04/23] paste as inline link & multisection for paste as ref --- Default.sublime-commands | 4 ++++ messages/2.1.5.md | 3 ++- paste_as_reference.py | 51 +++++++++++++++++++++++++++------------- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Default.sublime-commands b/Default.sublime-commands index dcd52dea..553405c9 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -48,5 +48,9 @@ { "caption": "MarkdownEditing: Insert Numbered Reference...", "command": "insert_numbered_reference" + }, + { + "caption": "MarkdownEditing: Paste as Inline Link", + "command": "paste_as_inline_link" } ] diff --git a/messages/2.1.5.md b/messages/2.1.5.md index b1c4afb7..66088cb0 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -9,7 +9,8 @@ feedback you can use [GitHub issues][issues]. ## New Features -* Four new commands added to command pallete (Paste as Link, Paste as Reference, Insert Named Reference, Insert Numbered Reference) +* Four new commands added to command pallete (`Paste as Link`, `Paste as Reference`, `Insert Named Reference`, `Insert Numbered Reference`) +* New command: `Paste as Inline Link` ## Changes diff --git a/paste_as_reference.py b/paste_as_reference.py index a39d565e..8d62d51a 100644 --- a/paste_as_reference.py +++ b/paste_as_reference.py @@ -32,24 +32,43 @@ def is_url(contents): class PasteAsReferenceCommand(sublime_plugin.TextCommand): def run(self, edit): view = self.view - sel = view.sel()[0] - text = view.substr(sel) + edit_regions = [] + suggested_title = False contents = sublime.get_clipboard() - if is_url(contents): - suggested_title = suggest_default_link_name(text) - link = contents - else: - suggested_title = suggest_default_link_name(contents) - link = '' - - edit_position = sel.end() + 3 - self.view.replace(edit, sel, "[" + text + "][" + suggested_title + "]") - reference_region = append_reference_link(edit, view, suggested_title, link) - sel = view.sel() - sel.clear() - sel.add(sublime.Region(edit_position, edit_position + len(suggested_title))) - sel.add(reference_region) + for sel in view.sel(): + text = view.substr(sel) + if not suggested_title: + if is_url(contents): + suggested_title = suggest_default_link_name(text) + link = contents + else: + suggested_title = suggest_default_link_name(contents) + link = '' + edit_position = sel.end() + 3 + self.view.replace(edit, sel, "[" + text + "][" + suggested_title + "]") + edit_regions.append(sublime.Region(edit_position, edit_position + len(suggested_title))) + if len(edit_regions) > 0: + selection = view.sel() + selection.clear() + reference_region = append_reference_link(edit, view, suggested_title, link) + selection.add(reference_region) + selection.add_all(edit_regions) def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) + +class PasteAsInlineLinkCommand(sublime_plugin.TextCommand): + def run(self, edit): + view = self.view + edit_regions = [] + suggested_title = False + contents = sublime.get_clipboard() + for sel in view.sel(): + text = view.substr(sel) + edit_position = sel.end() + 3 + self.view.replace(edit, sel, "[" + text + "](" + contents + ")") + edit_regions.append(sublime.Region(edit_position, edit_position + len(contents))) + if len(edit_regions) > 0: + selection.clear() + selection.add_all(edit_regions) From 36653f37da7618ccc49708111a0272082737012f Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 16 Dec 2015 15:10:14 +0800 Subject: [PATCH 05/23] paste image link --- Default.sublime-commands | 8 +++++++ messages/2.1.5.md | 7 ++++--- paste_as_reference.py | 45 +++++++++++++++++++++++++++++++--------- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/Default.sublime-commands b/Default.sublime-commands index 553405c9..c99e79f6 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -52,5 +52,13 @@ { "caption": "MarkdownEditing: Paste as Inline Link", "command": "paste_as_inline_link" + }, + { + "caption": "MarkdownEditing: Paste as Inline Image", + "command": "paste_as_inline_image" + }, + { + "caption": "MarkdownEditing: Paste as Image", + "command": "paste_as_image" } ] diff --git a/messages/2.1.5.md b/messages/2.1.5.md index 66088cb0..fe6057ea 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -9,11 +9,12 @@ feedback you can use [GitHub issues][issues]. ## New Features -* Four new commands added to command pallete (`Paste as Link`, `Paste as Reference`, `Insert Named Reference`, `Insert Numbered Reference`) -* New command: `Paste as Inline Link` +* Four new commands added to command pallete (`Paste as Link`, `Paste as Reference`, `Insert Named Reference`, `Insert Numbered Reference`). +* New command: `Paste as Inline Link`. +* New command: `Paste as Inline Image`, `Paste as Image`. ## Changes -* "Paste As Reference" works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. +* `Paste As Reference` works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. [issues]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues diff --git a/paste_as_reference.py b/paste_as_reference.py index 8d62d51a..70f70c76 100644 --- a/paste_as_reference.py +++ b/paste_as_reference.py @@ -13,14 +13,14 @@ def append_reference_link(edit, view, title, url): view.insert(edit, view.size(), '{0}[{1}]: {2}\n'.format(nl, title, url)) return sublime.Region(edit_position, edit_position + len(title)) -def suggest_default_link_name(title): +def suggest_default_link_name(title, image): # Camel case impl. ret = '' for word in title.split(): ret += word.capitalize() if len(ret) > 30: break - return 'link' + ret + return ('image' if image else 'link') + ret def is_url(contents): # If the clipboard contains an URL, return it @@ -30,23 +30,27 @@ def is_url(contents): return True if m else False class PasteAsReferenceCommand(sublime_plugin.TextCommand): - def run(self, edit): + def run(self, edit, image = False): view = self.view edit_regions = [] suggested_title = False - contents = sublime.get_clipboard() + contents = sublime.get_clipboard().strip() for sel in view.sel(): text = view.substr(sel) if not suggested_title: if is_url(contents): - suggested_title = suggest_default_link_name(text) + suggested_title = suggest_default_link_name(text, image) link = contents else: - suggested_title = suggest_default_link_name(contents) + suggested_title = suggest_default_link_name(contents, image) link = '' edit_position = sel.end() + 3 - self.view.replace(edit, sel, "[" + text + "][" + suggested_title + "]") + if image: + edit_position += 1 + self.view.replace(edit, sel, "![" + text + "][" + suggested_title + "]") + else: + self.view.replace(edit, sel, "[" + text + "][" + suggested_title + "]") edit_regions.append(sublime.Region(edit_position, edit_position + len(suggested_title))) if len(edit_regions) > 0: selection = view.sel() @@ -59,16 +63,37 @@ def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) class PasteAsInlineLinkCommand(sublime_plugin.TextCommand): - def run(self, edit): + def run(self, edit, image = False): view = self.view edit_regions = [] suggested_title = False - contents = sublime.get_clipboard() + contents = sublime.get_clipboard().strip() for sel in view.sel(): text = view.substr(sel) edit_position = sel.end() + 3 - self.view.replace(edit, sel, "[" + text + "](" + contents + ")") + if image: + edit_position += 1 + self.view.replace(edit, sel, "![" + text + "](" + contents + ")") + else: + self.view.replace(edit, sel, "[" + text + "](" + contents + ")") edit_regions.append(sublime.Region(edit_position, edit_position + len(contents))) if len(edit_regions) > 0: selection.clear() selection.add_all(edit_regions) + + def is_enabled(self): + return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) + +class PasteAsInlineImage(sublime_plugin.TextCommand): + def run(self, edit): + self.view.run_command("paste_as_inline_link", {"image": True}) + + def is_enabled(self): + return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) + +class PasteAsImage(sublime_plugin.TextCommand): + def run(self, edit): + self.view.run_command("paste_as_reference", {"image": True}) + + def is_enabled(self): + return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) \ No newline at end of file From 6a3c29d747010896ea85480bfb98f93e85b3daec Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 16 Dec 2015 15:18:00 +0800 Subject: [PATCH 06/23] remove dup --- messages/2.1.5.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/messages/2.1.5.md b/messages/2.1.5.md index 0fb6ab79..41b9c059 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -15,10 +15,6 @@ feedback you can use [GitHub issues][issues]. ## Changes -* `Paste As Reference` works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. - -## New Features - -## Changes +* `Paste As Reference` works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. [issues]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues From 6ce2feed082ec3d3bdbdddada5924f16a0882e55 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 16 Dec 2015 15:58:29 +0800 Subject: [PATCH 07/23] footnote uses selected word as name related #307 --- footnotes.py | 33 ++++++++++++++++++++++----------- messages/2.1.5.md | 1 + 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/footnotes.py b/footnotes.py index 6b4f5cb7..4142872e 100644 --- a/footnotes.py +++ b/footnotes.py @@ -90,20 +90,33 @@ def run(self, edit): def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) +def suggest_default_link_name(title): + # Camel case impl. + ret = '' + for word in title.split(): + ret += word.capitalize() + if len(ret) > 30: + break + return ret class InsertFootnoteCommand(sublime_plugin.TextCommand): def run(self, edit): - startloc = self.view.sel()[-1].end() - markernum = get_next_footnote_marker(self.view) - if bool(self.view.size()): - targetloc = self.view.find('(\s|$)', startloc).begin() + view = self.view + sel = view.sel()[-1] + startloc = sel.end() + if len(sel) > 0: + markernum = suggest_default_link_name(view.substr(sel)) + else: + markernum = get_next_footnote_marker(view) + if bool(view.size()): + targetloc = view.find('(\s|$)', startloc).begin() else: targetloc = 0 - self.view.insert(edit, targetloc, '[^%s]' % markernum) - self.view.insert(edit, self.view.size(), '\n [^%s]: ' % markernum) - self.view.run_command('set_motion', {"inclusive": True, "motion": "move_to", "motion_args": {"extend": True, "to": "eof"}}) - if self.view.settings().get('command_mode'): - self.view.run_command('enter_insert_mode', {"insert_command": "move", "insert_args": {"by": "characters", "forward": True}}) + view.insert(edit, targetloc, '[^%s]' % markernum) + view.insert(edit, view.size(), '\n [^%s]: ' % markernum) + view.run_command('set_motion', {"inclusive": True, "motion": "move_to", "motion_args": {"extend": True, "to": "eof"}}) + if view.settings().get('command_mode'): + view.run_command('enter_insert_mode', {"insert_command": "move", "insert_args": {"by": "characters", "forward": True}}) def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) @@ -177,8 +190,6 @@ def is_enabled(self): class SortFootnotesCommand(sublime_plugin.TextCommand): def run(self, edit): strip_trailing_whitespace(self.view, edit) - self.view.end_edit(edit) - edit = self.view.begin_edit() defs = get_footnote_definition_markers(self.view) notes = {} erase = [] diff --git a/messages/2.1.5.md b/messages/2.1.5.md index 41b9c059..da64a779 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -16,5 +16,6 @@ feedback you can use [GitHub issues][issues]. ## Changes * `Paste As Reference` works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. +* `Insert Footnote` (`alt+shift+6`) now uses selected words (if any) as footnote marker name instead of number. [issues]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues From 35de43dab7601f96a83be629414776b9b225c50c Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Thu, 17 Dec 2015 09:55:25 +0800 Subject: [PATCH 08/23] Increment link reference definition related #119 --- Default (Linux).sublime-keymap | 11 ++++++++++- Default (OSX).sublime-keymap | 11 ++++++++++- Default (Windows).sublime-keymap | 11 ++++++++++- Markdown.sublime-settings | 2 +- messages/2.1.5.md | 1 + numbered_list.py | 14 ++++++++++++++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index efa43abf..67e8b98c 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -344,11 +344,20 @@ { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, + // Extend Numbered Reference + { "keys": ["enter"], "command": "number_list_reference", "context": + [ + { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\S*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, + { "key": "auto_complete_visible", "operator": "equal", "operand": false }, + { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } + ] + }, // Remove empty list item { "keys": ["enter"], "command": "run_macro_file", "args": {"file": "Packages/MarkdownEditing/macros/Remove Empty List Item.sublime-macro"}, "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*([*\\-+]|\\d+\\.)\\s+)$", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*(\\[\\d+\\]:|[*\\-+]|\\d+\\.)\\s+)$", "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^\\s*$", "match_all": true }, { "key": "auto_complete_visible", "operator": "equal", "operand": false }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index f6e2c8ab..dfca7508 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -344,11 +344,20 @@ { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, + // Extend Numbered Reference + { "keys": ["enter"], "command": "number_list_reference", "context": + [ + { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\S*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, + { "key": "auto_complete_visible", "operator": "equal", "operand": false }, + { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } + ] + }, // Remove empty list item { "keys": ["enter"], "command": "run_macro_file", "args": {"file": "Packages/MarkdownEditing/macros/Remove Empty List Item.sublime-macro"}, "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*([*\\-+]|\\d+\\.)\\s+)$", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*(\\[\\d+\\]:|[*\\-+]|\\d+\\.)\\s+)$", "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^\\s*$", "match_all": true }, { "key": "auto_complete_visible", "operator": "equal", "operand": false }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index efa43abf..67e8b98c 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -344,11 +344,20 @@ { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, + // Extend Numbered Reference + { "keys": ["enter"], "command": "number_list_reference", "context": + [ + { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\S*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, + { "key": "auto_complete_visible", "operator": "equal", "operand": false }, + { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } + ] + }, // Remove empty list item { "keys": ["enter"], "command": "run_macro_file", "args": {"file": "Packages/MarkdownEditing/macros/Remove Empty List Item.sublime-macro"}, "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*([*\\-+]|\\d+\\.)\\s+)$", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*(\\[\\d+\\]:|[*\\-+]|\\d+\\.)\\s+)$", "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^\\s*$", "match_all": true }, { "key": "auto_complete_visible", "operator": "equal", "operand": false }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } diff --git a/Markdown.sublime-settings b/Markdown.sublime-settings index 28885752..cf048027 100644 --- a/Markdown.sublime-settings +++ b/Markdown.sublime-settings @@ -59,7 +59,7 @@ "mde.keep_centered": true }, - "mde.lint":{ + "mde.lint": { // disabled rules, e.g. "md001". "disable": ["md013"], // Options: diff --git a/messages/2.1.5.md b/messages/2.1.5.md index da64a779..9aaab760 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -12,6 +12,7 @@ feedback you can use [GitHub issues][issues]. * Four new commands added to command pallete (`Paste as Link`, `Paste as Reference`, `Insert Named Reference`, `Insert Numbered Reference`). * New command: `Paste as Inline Link`. * New command: `Paste as Inline Image`, `Paste as Image`. +* Increment link reference defition on Enter (e.g. `[27]: http://www.example.org`). ## Changes diff --git a/numbered_list.py b/numbered_list.py index 16c44173..82d48b81 100644 --- a/numbered_list.py +++ b/numbered_list.py @@ -17,3 +17,17 @@ def run(self, edit): def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) + +class NumberListReferenceCommand(sublime_plugin.TextCommand): + def run(self, edit): + view = self.view + sel = view.sel()[0] + text = view.substr(view.full_line(sel)) + num = re.search('\d', text).start() + dot = text.find("]") + if num == 0: + view.erase(edit, sel) + view.insert(edit, sel.begin(), "\n%d]: " % (int(text[:dot]) + 1,)) + else: + view.erase(edit, sel) + view.insert(edit, sel.begin(), "\n%s%d]: " % (text[:num], int(text[num:dot]) + 1)) \ No newline at end of file From a8d7bd379584be3199f05b2ba609091bdfb4c2d0 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 18 Dec 2015 08:45:54 +0800 Subject: [PATCH 09/23] fix false trigger of increment link reference definition --- Default (Linux).sublime-keymap | 2 +- Default (OSX).sublime-keymap | 2 +- Default (Windows).sublime-keymap | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index 67e8b98c..ebdb2c34 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -348,7 +348,7 @@ { "keys": ["enter"], "command": "number_list_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\S*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, { "key": "auto_complete_visible", "operator": "equal", "operand": false }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index dfca7508..0499a3f6 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -348,7 +348,7 @@ { "keys": ["enter"], "command": "number_list_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\S*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, { "key": "auto_complete_visible", "operator": "equal", "operand": false }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index 67e8b98c..ebdb2c34 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -348,7 +348,7 @@ { "keys": ["enter"], "command": "number_list_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\S*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "^(\\s*\\[(\\d+)\\]:\\s*)\\S.*", "match_all": true }, { "key": "auto_complete_visible", "operator": "equal", "operand": false }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] From 725c340e076fc58929b7a2cd3a517cc4648ca716 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 18 Dec 2015 09:17:30 +0800 Subject: [PATCH 10/23] re-enable default Markdown package upon uninstallation fix #284 code inspired by https://packagecontrol.io/docs/events --- bootstrap.py | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/bootstrap.py b/bootstrap.py index dd2b9f6f..d7e597a1 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -1,15 +1,42 @@ -import sublime +import sys +package_name = 'MarkdownEditing' -def plugin_loaded(): - # Native package causes some conflicts. - disable_native_markdown_package() - -def disable_native_markdown_package(): +def get_ingored_packages(): settings = sublime.load_settings('Preferences.sublime-settings') - ignored_packages = settings.get('ignored_packages', []) + return settings.get('ignored_packages', []) +def save_ingored_packages(ignored_packages): + settings.set('ignored_packages', ignored_packages) + sublime.save_settings('Preferences.sublime-settings') + +def disable_native_markdown_package(): + ignored_packages = get_ingored_packages() if 'Markdown' not in ignored_packages: ignored_packages.append('Markdown') - settings.set('ignored_packages', ignored_packages) - sublime.save_settings('Preferences.sublime-settings') + save_ingored_packages(ignored_packages) + +def enable_native_markdown_packageb(): + ignored_packages = get_ingored_packages() + if 'Markdown' in ignored_packages: + ignored_packages.remove('Markdown') + save_ingored_packages(ignored_packages) + +def plugin_loaded(): + from package_control import events + + if events.install(package_name): + # Native package causes some conflicts. + disable_native_markdown_package() + +def plugin_unloaded(): + from package_control import events + + if events.remove(package_name): + # Native package causes some conflicts. + enable_native_markdown_package() + +# Compat with ST2 +if sys.version_info < (3,): + plugin_loaded() + unload_handler = plugin_unloaded \ No newline at end of file From fca2f0675d323a21fe500651c45250c0fc55bfee Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 18 Dec 2015 10:48:47 +0800 Subject: [PATCH 11/23] merge "insert named reference" into "paste as ref" --- Default (Linux).sublime-keymap | 5 ---- Default (OSX).sublime-keymap | 5 ---- Default (Windows).sublime-keymap | 5 ---- insert_references.py | 49 -------------------------------- messages/2.1.5.md | 1 + paste_as_reference.py | 49 +++++++++++++++++++++----------- 6 files changed, 33 insertions(+), 81 deletions(-) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index ebdb2c34..05461987 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -454,11 +454,6 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["alt+ctrl+r"], "command": "insert_named_reference", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, { "keys": ["super+ctrl+shift+r"], "command": "insert_numbered_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index 0499a3f6..791c992a 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -454,11 +454,6 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["super+ctrl+r"], "command": "insert_named_reference", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, { "keys": ["super+ctrl+shift+r"], "command": "insert_numbered_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index ebdb2c34..05461987 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -454,11 +454,6 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["alt+ctrl+r"], "command": "insert_named_reference", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, { "keys": ["super+ctrl+shift+r"], "command": "insert_numbered_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } diff --git a/insert_references.py b/insert_references.py index cc78cfd4..3ff3f6f9 100644 --- a/insert_references.py +++ b/insert_references.py @@ -68,55 +68,6 @@ def run(self, edit, title): def insert_references(view, title): view.run_command("insert_references", {"title": title}) -# Inspired by http://www.leancrew.com/all-this/2012/08/markdown-reference-links-in-bbedit/ -# Appends a new reference link to end of document, using a user-input name and URL. -# Then inserts a reference to the link at the current selection(s). - -class InsertNamedReferenceCommand(sublime_plugin.TextCommand): - - def description(self): - return 'Insert Numbered Reference Link' - - def run(self, edit): - self.view.window().show_input_panel( - 'URL to link to:', - get_clipboard_if_url(), - self.receive_link, - None, None) - - def receive_link(self, linkurl): - linkurl = mangle_url(linkurl) - - newref = check_for_link(self.view, linkurl) - if newref: - # Link already exists, reuse existing reference - self.insert_link(linkurl, newref, False) - - else: - self.view.window().show_input_panel( - 'Name for reference:', '', - lambda newref: self.insert_link(linkurl, newref), - None, None) - - def insert_link(self, linkurl, newref, actually_insert=True): - # Check if title is already present as reference - if actually_insert and self.view.find(r'^\s{0,3}\[' + re.escape(newref) + '\]:[ \t]+', 0): - sublime.error_message('A reference named "' + newref + '" already exists.') - self.view.window().show_input_panel( - 'Name for reference:', '', - lambda newref: self.insert_link(linkurl, newref), - None, None) - return - - if actually_insert: - append_reference_link(self.view, newref, linkurl) - else: - insert_references(self.view, newref) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) - - # Inspired by http://www.leancrew.com/all-this/2012/08/markdown-reference-links-in-bbedit/ # Appends a new reference link to end of document, using an autoincrementing number as the reference title. # Then inserts a reference to the link at the current selection(s). diff --git a/messages/2.1.5.md b/messages/2.1.5.md index 9aaab760..c147c74c 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -18,5 +18,6 @@ feedback you can use [GitHub issues][issues]. * `Paste As Reference` works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. * `Insert Footnote` (`alt+shift+6`) now uses selected words (if any) as footnote marker name instead of number. +* Removed `Insert Named Reference` command, you are encouraged to use `Paste as Reference` instead. [issues]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues diff --git a/paste_as_reference.py b/paste_as_reference.py index 70f70c76..bc5ad68d 100644 --- a/paste_as_reference.py +++ b/paste_as_reference.py @@ -16,11 +16,15 @@ def append_reference_link(edit, view, title, url): def suggest_default_link_name(title, image): # Camel case impl. ret = '' - for word in title.split(): - ret += word.capitalize() - if len(ret) > 30: - break - return ('image' if image else 'link') + ret + title_segs = title.split() + if len(title_segs) > 1: + for word in title_segs: + ret += word.capitalize() + if len(ret) > 30: + break + return ('image' if image else 'link') + ret + else: + return title def is_url(contents): # If the clipboard contains an URL, return it @@ -29,22 +33,32 @@ def is_url(contents): m = re_match_urls.search(contents) return True if m else False +def mangle_url(url): + url = url.strip() + if re.match(r'^([a-z0-9-]+\.)+\w{2,4}', url, re.IGNORECASE): + url = 'http://' + url + return url + +def check_for_link(view, url): + titles = [] + # Check if URL is already present as reference link + view.find_all(r'^\s{0,3}\[([^^\]]+)\]:[ \t]+' + re.escape(url) + '$', 0, '$1', titles) + return titles[0] if titles else None + class PasteAsReferenceCommand(sublime_plugin.TextCommand): def run(self, edit, image = False): view = self.view edit_regions = [] - suggested_title = False contents = sublime.get_clipboard().strip() + link = mangle_url(contents) if is_url(contents) else "" + if len(link) > 0: + # If link already exists, reuse existing reference + suggested_link_name = suggested_title = check_for_link(view, link) for sel in view.sel(): text = view.substr(sel) if not suggested_title: - if is_url(contents): - suggested_title = suggest_default_link_name(text, image) - link = contents - else: - suggested_title = suggest_default_link_name(contents, image) - link = '' - + suggested_link_name = suggest_default_link_name(text, image) + suggested_title = suggested_link_name if suggested_link_name != text else "" edit_position = sel.end() + 3 if image: edit_position += 1 @@ -55,7 +69,7 @@ def run(self, edit, image = False): if len(edit_regions) > 0: selection = view.sel() selection.clear() - reference_region = append_reference_link(edit, view, suggested_title, link) + reference_region = append_reference_link(edit, view, suggested_link_name, link) selection.add(reference_region) selection.add_all(edit_regions) @@ -68,15 +82,16 @@ def run(self, edit, image = False): edit_regions = [] suggested_title = False contents = sublime.get_clipboard().strip() + link = mangle_url(contents) if is_url(contents) else "" for sel in view.sel(): text = view.substr(sel) edit_position = sel.end() + 3 if image: edit_position += 1 - self.view.replace(edit, sel, "![" + text + "](" + contents + ")") + self.view.replace(edit, sel, "![" + text + "](" + link + ")") else: - self.view.replace(edit, sel, "[" + text + "](" + contents + ")") - edit_regions.append(sublime.Region(edit_position, edit_position + len(contents))) + self.view.replace(edit, sel, "[" + text + "](" + link + ")") + edit_regions.append(sublime.Region(edit_position, edit_position + len(link))) if len(edit_regions) > 0: selection.clear() selection.add_all(edit_regions) From 9c56bc4a50de5e6807698f16435c119b79db42eb Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 18 Dec 2015 11:02:26 +0800 Subject: [PATCH 12/23] remove "illegal" link space highlight --- MarkdownEditor-Dark.tmTheme | 2 -- MarkdownEditor-Focus.tmTheme | 2 -- MarkdownEditor-Yellow.tmTheme | 2 -- MarkdownEditor.tmTheme | 2 -- messages/2.1.5.md | 1 + 5 files changed, 1 insertion(+), 8 deletions(-) diff --git a/MarkdownEditor-Dark.tmTheme b/MarkdownEditor-Dark.tmTheme index f03b5849..f35a0f41 100644 --- a/MarkdownEditor-Dark.tmTheme +++ b/MarkdownEditor-Dark.tmTheme @@ -81,8 +81,6 @@ invalid.illegal settings - background - #06cdcd fontStyle foreground diff --git a/MarkdownEditor-Focus.tmTheme b/MarkdownEditor-Focus.tmTheme index e05e5972..11a7b5b1 100644 --- a/MarkdownEditor-Focus.tmTheme +++ b/MarkdownEditor-Focus.tmTheme @@ -92,8 +92,6 @@ invalid.illegal settings - background - #F93232 fontStyle foreground diff --git a/MarkdownEditor-Yellow.tmTheme b/MarkdownEditor-Yellow.tmTheme index c3c6a41b..4707d76c 100644 --- a/MarkdownEditor-Yellow.tmTheme +++ b/MarkdownEditor-Yellow.tmTheme @@ -81,8 +81,6 @@ invalid.illegal settings - background - #fa3127 fontStyle foreground diff --git a/MarkdownEditor.tmTheme b/MarkdownEditor.tmTheme index f288ae92..a71dc710 100644 --- a/MarkdownEditor.tmTheme +++ b/MarkdownEditor.tmTheme @@ -81,8 +81,6 @@ invalid.illegal settings - background - #F93232 fontStyle foreground diff --git a/messages/2.1.5.md b/messages/2.1.5.md index c147c74c..fc787f9e 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -19,5 +19,6 @@ feedback you can use [GitHub issues][issues]. * `Paste As Reference` works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. * `Insert Footnote` (`alt+shift+6`) now uses selected words (if any) as footnote marker name instead of number. * Removed `Insert Named Reference` command, you are encouraged to use `Paste as Reference` instead. +* Space between two link parts will not be highlighted. [issues]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues From f3e304375505892f2a0ca3650ef554222f42b5dd Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 18 Dec 2015 12:00:54 +0800 Subject: [PATCH 13/23] fix linter + md030 --- Default (Linux).sublime-keymap | 5 ---- Default (OSX).sublime-keymap | 5 ---- Default (Windows).sublime-keymap | 5 ---- Markdown (Standard).sublime-settings | 11 +++++++- Markdown.sublime-settings | 12 ++++++++- MultiMarkdown.sublime-settings | 11 +++++++- lint.py | 38 +++++++++++++++++++++------- 7 files changed, 60 insertions(+), 27 deletions(-) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index 05461987..a3fa5afe 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -651,10 +651,5 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "preceding_text", "operator": "regex_contains", "operand": "(> )+", "match_all": true } ] - }, - { "keys": ["ctrl+shift+m"], "command": "lint", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] } ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index 791c992a..3c393f6d 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -651,10 +651,5 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "preceding_text", "operator": "regex_contains", "operand": "(> )+", "match_all": true } ] - }, - { "keys": ["super+shift+m"], "command": "lint", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] } ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index 05461987..a3fa5afe 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -651,10 +651,5 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "preceding_text", "operator": "regex_contains", "operand": "(> )+", "match_all": true } ] - }, - { "keys": ["ctrl+shift+m"], "command": "lint", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] } ] diff --git a/Markdown (Standard).sublime-settings b/Markdown (Standard).sublime-settings index b1b75aef..9f78a2d4 100644 --- a/Markdown (Standard).sublime-settings +++ b/Markdown (Standard).sublime-settings @@ -77,6 +77,15 @@ // one, '1.' only // ordered, ascending number // any, consistent within one list - "md029": "any" + "md029": "any", + // (ordered vs unordered, single-line vs multi-line) + "md030": { + "ul_single": 1, + "ol_single": 1, + // optinally, 3 + "ul_multi": 1, + // optionaly, 2 + "ol_multi": 1 + } } } diff --git a/Markdown.sublime-settings b/Markdown.sublime-settings index cf048027..4fdd52eb 100644 --- a/Markdown.sublime-settings +++ b/Markdown.sublime-settings @@ -88,6 +88,16 @@ // one, '1.' only // ordered, ascending number // any, consistent within one list - "md029": "any" + "md029": "any", + // Number of spaces after list markers depending on list type. + // (ordered vs unordered, single-line vs multi-line) + "md030": { + "ul_single": 1, + "ol_single": 1, + // optinally, 3 + "ul_multi": 1, + // optionaly, 2 + "ol_multi": 1 + } } } diff --git a/MultiMarkdown.sublime-settings b/MultiMarkdown.sublime-settings index 35a504c9..6f2cd4fd 100644 --- a/MultiMarkdown.sublime-settings +++ b/MultiMarkdown.sublime-settings @@ -82,6 +82,15 @@ // one, '1.' only // ordered, ascending number // any, consistent within one list - "md029": "any" + "md029": "any", + // (ordered vs unordered, single-line vs multi-line) + "md030": { + "ul_single": 1, + "ol_single": 1, + // optinally, 3 + "ul_multi": 1, + // optionaly, 2 + "ol_multi": 1 + } } } diff --git a/lint.py b/lint.py index 26663edf..f6cd67db 100644 --- a/lint.py +++ b/lint.py @@ -124,14 +124,8 @@ def test(self, text, s, e): mr = re.search(self.eol, rest, re.M) end = mr.start(0) if mr else len(rest) block = rest[:end] - #print('====') - #print(block) - #print('====') mrs = re.finditer(r'^(\s*)([*\-+])\s+', block, re.M) for mr in mrs: - #print('====') - #print(mr.group(2)) - #print('====') self.lastpos = e + 1 + mr.end(0) sym = mr.group(2) (ans, exp) = self.testsingle(sym) @@ -150,9 +144,6 @@ def test(self, text, s, e): break lv = len(lvstack) lvstack.append(nspaces) - #print(sym) - #print(lv) - #print(self.lvs) (ans, exp) = self.testcyc(sym, lv) if ans is False: ret[e + 1 + @@ -632,6 +623,35 @@ def test(self, text, s, e): return ret +class md030(mddef): + flag = re.M + desc = 'Ordered list item prefix' + locator = r'^ {0,3}(([0-9]+\.)|[*+-])(?=\s)' + gid = 1 + + def test(self, text, s, e): + sym = text[s:e] + mr = re.match(r'[0-9]+\.', sym) + if mr: + single = self.settings['ol_single'] + multi = self.settings['ol_multi'] + else: + single = self.settings['ul_single'] + multi = self.settings['ul_multi'] + nspaces = 0 + p = e + while text[p] == ' ': + p += 1 + nspaces += 1 + while text[p] != '\n' and text[p] != '\r': + p += 1 + ret = {} + is_multi = (len(text) >= p + 2) and (text[p + 1] in '\r\n') + against_value = multi if is_multi else single + if against_value != nspaces: + ret[e] = '%d spaces found, %d expected' % (nspaces, against_value) + return ret + class MarkdownLintCommand(sublime_plugin.TextCommand): blockdef = [] From 3981f83a6af59a7641552872452b60610e30dc34 Mon Sep 17 00:00:00 2001 From: Ali Ayas Date: Sun, 20 Dec 2015 15:14:35 +0200 Subject: [PATCH 14/23] Wrap changelog file for better readibility --- messages/2.1.5.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/messages/2.1.5.md b/messages/2.1.5.md index fc787f9e..a3337fa0 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -5,20 +5,27 @@ feedback you can use [GitHub issues][issues]. ## Bug Fixes -* "Insert References" commands get fixed. Select something and press `alt+ctrl+r` to try `insert_named_reference` command, and `super+ctrl+shift+r` to try `insert_numbered_reference`. +* "Insert References" commands get fixed. Select something and press `alt+ctrl+r` + to try `insert_named_reference` command, and `super+ctrl+shift+r` to try + `insert_numbered_reference`. ## New Features -* Four new commands added to command pallete (`Paste as Link`, `Paste as Reference`, `Insert Named Reference`, `Insert Numbered Reference`). -* New command: `Paste as Inline Link`. -* New command: `Paste as Inline Image`, `Paste as Image`. -* Increment link reference defition on Enter (e.g. `[27]: http://www.example.org`). +* Four new commands added to command pallete (`Paste as Link`, `Paste as Reference`, + `Insert Named Reference`, `Insert Numbered Reference`). +* New command: `Paste as Inline Link`. +* New command: `Paste as Inline Image`, `Paste as Image`. +* Increment link reference defition on Enter (e.g. `[27]: http://www.example.org`). ## Changes -* `Paste As Reference` works differently now. Depending on whether the clipboard content is a valid URL, `super+ctrl+r` generates a reference on your selection with clipboard content as URL link or link name. -* `Insert Footnote` (`alt+shift+6`) now uses selected words (if any) as footnote marker name instead of number. -* Removed `Insert Named Reference` command, you are encouraged to use `Paste as Reference` instead. -* Space between two link parts will not be highlighted. +* `Paste As Reference` works differently now. Depending on whether the clipboard + content is a valid URL, `super+ctrl+r` generates a reference on your selection + with clipboard content as URL link or link name. +* `Insert Footnote` (`alt+shift+6`) now uses selected words (if any) as footnote + marker name instead of number. +* Removed `Insert Named Reference` command, you are encouraged to use + `Paste as Reference` instead. +* Space between two link parts will not be highlighted. [issues]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues From 6520b0b7db3c15b685335924606f9f07daa0e69c Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Thu, 24 Dec 2015 11:51:21 +0800 Subject: [PATCH 15/23] replace sync listeners with async --- distraction_free_mode.py | 2 +- footnotes.py | 12 +++++++++--- messages/2.1.5.md | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/distraction_free_mode.py b/distraction_free_mode.py index 601cbcc2..19ddf22d 100644 --- a/distraction_free_mode.py +++ b/distraction_free_mode.py @@ -18,7 +18,7 @@ def view_is_markdown(view): return False class KeepCurrentLineCentered(sublime_plugin.EventListener): - def on_modified(self, view): + def on_modified_async(self, view): # One of the MarkdownEditing syntax files must be in use. if not view_is_markdown(view): return False diff --git a/footnotes.py b/footnotes.py index 4142872e..2ff1707c 100644 --- a/footnotes.py +++ b/footnotes.py @@ -64,13 +64,19 @@ def strip_trailing_whitespace(view, edit): if tws: view.erase(edit, tws) +def view_is_markdown(view): + if len(view.sel()) > 0: + return bool(view.score_selector(view.sel()[0].a, "text.html.markdown")) + else: + return False class MarkFootnotes(sublime_plugin.EventListener): def update_footnote_data(self, view): - view.add_regions(REFERENCE_KEY, view.find_all(REFERENCE_REGEX), '', 'cross', sublime.HIDDEN) - view.add_regions(DEFINITION_KEY, view.find_all(DEFINITION_REGEX), '', 'cross', sublime.HIDDEN) + if view_is_markdown(view): + view.add_regions(REFERENCE_KEY, view.find_all(REFERENCE_REGEX), '', 'cross', sublime.HIDDEN) + view.add_regions(DEFINITION_KEY, view.find_all(DEFINITION_REGEX), '', 'cross', sublime.HIDDEN) - def on_modified(self, view): + def on_modified_async(self, view): self.update_footnote_data(view) def on_load(self, view): diff --git a/messages/2.1.5.md b/messages/2.1.5.md index a3337fa0..219017f3 100644 --- a/messages/2.1.5.md +++ b/messages/2.1.5.md @@ -8,6 +8,7 @@ feedback you can use [GitHub issues][issues]. * "Insert References" commands get fixed. Select something and press `alt+ctrl+r` to try `insert_named_reference` command, and `super+ctrl+shift+r` to try `insert_numbered_reference`. +* Fix an issue that Sublime Text may freeze when searching in a large project. ## New Features From 4e1825966f619e6f4be82dad268ba8db1f0b53b4 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 25 Dec 2015 17:54:50 +0800 Subject: [PATCH 16/23] refer to blackboard theme so we can close #173 --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c11e159..d4a68761 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Markdown plugin for Sublime Text. Provides a decent Markdown color scheme (light ![MarkdownEditing][github] -[Dark][github 2] and [yellow][github 3] theme available. +[Dark][github 2] and [yellow][github 3] theme available ([additional](#additional-color-themes)). ## Overview @@ -149,6 +149,10 @@ In order to activate the dark or the yellow theme, put one of these lines to you If you want to go with your already existing theme, you can reenable it with the same method as above. Keep in mind that, that theme may not cover all the parts of the Markdown syntax that this plugin defines. +### Additional color themes: + +- [Blackboard theme][linkBlackboardTheme] by [@mdesantis][mdesantis] + By default, when you install the plugin, files with these extensions will be assigned to Markdown syntax: "md", "txt", "mdown", "markdown", "markdn". If you want to prevent any of these extensions to be opened as Markdown, follow these steps: 1. Click on the language menu at bottom right @@ -225,3 +229,5 @@ MarkdownEditing is released under the [MIT License][opensource]. [Wiki]: https://github.com/SublimeText-Markdown/MarkdownEditing/wiki [GFM]: https://help.github.com/articles/github-flavored-markdown [#158]: https://github.com/SublimeText-Markdown/MarkdownEditing/issues/158 +[linkBlackboardTheme]: https://github.com/mdesantis/MarkdownEditing/blob/blackboard-theme/MarkdownEditor-Blackboard.tmTheme +[mdesantis]: https://github.com/mdesantis From 59d163aeb44f9afe6ab7c99611d4512800ce3630 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Tue, 29 Dec 2015 15:04:24 +0800 Subject: [PATCH 17/23] add me to credits maybe I can get a dollar from that eventually --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d4a68761..1d3b9083 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ See `CONTRIBUTING.md` file. ## Credits -MarkdownEditing was originally created by [Brett Terpstra][brettterpstra] and has become a community project with the goal of consolidating the best features from the varied collection of Markdown packages for Sublime Text. Current development is headed up by [Ali Ayas][github 9]. +MarkdownEditing was originally created by [Brett Terpstra][brettterpstra] and has become a community project with the goal of consolidating the best features from the varied collection of Markdown packages for Sublime Text. Current development is headed up by [Ali Ayas][github 9] and [Felix Hao][github 10]. Related blog posts from Brett: * http://brettterpstra.com/2012/05/17/markdown-editing-for-sublime-text-2-humble-beginnings/ @@ -197,7 +197,8 @@ Footnote commands were submitted by [J. Nicholas Geist][github 4] and originated You can support [contributors](https://github.com/SublimeText-Markdown/MarkdownEditing/graphs/contributors) of this project individually. Every contributor is welcomed to add his/her line below with any content. Ordering shall be alphabetically by GitHub username. -* [@maliayas](https://github.com/maliayas): [paypal] ![donation received](http://maliayas.com/business/donation/badge.php?project=markdown_editing) +* [@felixhao28][github 10]: [paypal] +* [@maliayas][github 9]: [paypal] ![donation received](http://maliayas.com/business/donation/badge.php?project=markdown_editing) ## License @@ -220,6 +221,7 @@ MarkdownEditing is released under the [MIT License][opensource]. [github 7]: https://raw.github.com/SublimeText-Markdown/MarkdownEditing/master/screenshots/keyboard-shortcut.png [github 8]: https://raw.github.com/SublimeText-Markdown/MarkdownEditing/master/screenshots/strikethrough.png [github 9]: https://github.com/maliayas +[github 10]: https://github.com/felixhao28 [opensource]: http://www.opensource.org/licenses/MIT [wbond]: http://wbond.net/sublime_packages/package_control [wbond 2]: http://wbond.net/sublime_packages/package_control/installation From 09c5ffba340ace10d25dd659abbb1e7fa236e27a Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 30 Dec 2015 12:49:50 +0800 Subject: [PATCH 18/23] multi-selection support for magic footnotes and also fix crash when paste as reference when clipboard is not url --- footnotes.py | 41 ++++++++++++++++------------------------- paste_as_reference.py | 1 + 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/footnotes.py b/footnotes.py index 2ff1707c..2e43e85b 100644 --- a/footnotes.py +++ b/footnotes.py @@ -96,38 +96,29 @@ def run(self, edit): def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) -def suggest_default_link_name(title): - # Camel case impl. - ret = '' - for word in title.split(): - ret += word.capitalize() - if len(ret) > 30: - break - return ret - class InsertFootnoteCommand(sublime_plugin.TextCommand): def run(self, edit): view = self.view - sel = view.sel()[-1] - startloc = sel.end() - if len(sel) > 0: - markernum = suggest_default_link_name(view.substr(sel)) - else: - markernum = get_next_footnote_marker(view) - if bool(view.size()): - targetloc = view.find('(\s|$)', startloc).begin() - else: - targetloc = 0 - view.insert(edit, targetloc, '[^%s]' % markernum) - view.insert(edit, view.size(), '\n [^%s]: ' % markernum) - view.run_command('set_motion', {"inclusive": True, "motion": "move_to", "motion_args": {"extend": True, "to": "eof"}}) - if view.settings().get('command_mode'): - view.run_command('enter_insert_mode', {"insert_command": "move", "insert_args": {"by": "characters", "forward": True}}) + markernum = get_next_footnote_marker(view) + markernum_str = '[^%s]' % markernum + for sel in view.sel(): + startloc = sel.end() + if bool(view.size()): + targetloc = view.find('(\s|$)', startloc).begin() + else: + targetloc = 0 + view.insert(edit, targetloc, markernum_str) + if len(view.sel()) > 0: + view.insert(edit, view.size(), '\n ' + markernum_str + ': ') + view.sel().clear() + view.sel().add(sublime.Region(view.size(), view.size())) + view.run_command('set_motion', {"inclusive": True, "motion": "move_to", "motion_args": {"extend": True, "to": "eof"}}) + if view.settings().get('command_mode'): + view.run_command('enter_insert_mode', {"insert_command": "move", "insert_args": {"by": "characters", "forward": True}}) def is_enabled(self): return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) - class GoToFootnoteDefinitionCommand(sublime_plugin.TextCommand): def run(self, edit): defs = get_footnote_definition_markers(self.view) diff --git a/paste_as_reference.py b/paste_as_reference.py index bc5ad68d..f27331e6 100644 --- a/paste_as_reference.py +++ b/paste_as_reference.py @@ -51,6 +51,7 @@ def run(self, edit, image = False): edit_regions = [] contents = sublime.get_clipboard().strip() link = mangle_url(contents) if is_url(contents) else "" + suggested_title = "" if len(link) > 0: # If link already exists, reuse existing reference suggested_link_name = suggested_title = check_for_link(view, link) From d027915d86024e05a7b2295a11925dd4a8bd6b0c Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 30 Dec 2015 12:50:05 +0800 Subject: [PATCH 19/23] add footnotes command to command palette --- Default.sublime-commands | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Default.sublime-commands b/Default.sublime-commands index c99e79f6..357f6bb5 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -60,5 +60,13 @@ { "caption": "MarkdownEditing: Paste as Image", "command": "paste_as_image" + }, + { + "caption": "MarkdownEditing: Magic Footnotes Command", + "command": "magic_footnotes" + }, + { + "caption": "MarkdownEditing: Gather Missing Footnotes", + "command": "gather_missing_footnotes" } ] From d4c2a5ee6a7dc8bc6b311f3003abeb4b0dc49fa8 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Wed, 30 Dec 2015 14:06:06 +0800 Subject: [PATCH 20/23] only enable lint in markdown env --- lint.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lint.py b/lint.py index f6cd67db..7a3807d2 100644 --- a/lint.py +++ b/lint.py @@ -709,3 +709,6 @@ def test(self, tar, text): break return ret + + def is_enabled(self): + return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) From 802b489e3eec831e00d0049a79688d13f4bea7a2 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 1 Jan 2016 21:44:02 +0800 Subject: [PATCH 21/23] Happy New Year --- Default (Linux).sublime-keymap | 67 +---- Default (OSX).sublime-keymap | 67 +---- Default (Windows).sublime-keymap | 67 +---- Default.sublime-commands | 40 +-- Markdown (Standard).tmLanguage | 6 +- Markdown.tmLanguage | 51 +++- MarkdownEditor-Dark.tmTheme | 2 +- MarkdownEditor-Focus.tmTheme | 2 +- MarkdownEditor-Yellow.tmTheme | 2 +- MarkdownEditor.tmTheme | 2 +- README.md | 12 +- footnotes.py | 2 +- gather_missing_links.py | 24 -- insert_references.py | 103 ------- jumpToMarker.py | 26 -- list_markdown_references.py | 50 ---- mdeutils.py | 12 + paste_as_link.py | 13 - paste_as_reference.py | 115 -------- references.py | 469 +++++++++++++++++++++++++++++++ 20 files changed, 582 insertions(+), 550 deletions(-) delete mode 100644 gather_missing_links.py delete mode 100644 insert_references.py delete mode 100644 jumpToMarker.py delete mode 100644 list_markdown_references.py create mode 100644 mdeutils.py delete mode 100644 paste_as_link.py delete mode 100644 paste_as_reference.py create mode 100644 references.py diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index a3fa5afe..b0b89ccf 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -379,16 +379,6 @@ { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, - { "keys": ["alt+shift+g"], "command": "gather_missing_link_markers", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["alt+shift+f"], "command": "gather_missing_footnotes", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, { "keys": ["tab"], "command": "complete_underlined_header", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, @@ -399,42 +389,12 @@ ] }, - // inline link insertion - { "keys": ["ctrl+super+k"], "command": "insert_snippet", "args": {"contents": "[$1]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|$)", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['a-zA-Z0-9_]$", "match_all": true }, - { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.single", "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["ctrl+super+k"], "command": "insert_snippet", "args": {"contents": "[$SELECTION]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, // inline image insertion - { "keys": ["super+shift+k"], "command": "insert_snippet", "args": {"contents": "![$1]($0)"}, "context": + { "keys": ["super+shift+k"], "command": "reference_new_inline_image", "context": [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|$)", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['a-zA-Z0-9_]$", "match_all": true }, - { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.single", "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["super+shift+k"], "command": "insert_snippet", "args": {"contents": "![$SELECTION]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, // modify [] pairing so that selection is removed after pairing, ready for [] or () { "keys": ["["], "command": "insert_snippet", "args": {"contents": "[$SELECTION]$0"}, "context": [ @@ -444,27 +404,17 @@ ] }, // run paste as link command on selected text - { "keys": ["ctrl+super+v"], "command": "paste_as_link", "context": + { "keys": ["ctrl+super+v"], "command": "reference_new_inline_link", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["ctrl+super+r"], "command": "paste_as_reference", "context": + { "keys": ["ctrl+super+r"], "command": "reference_new_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["super+ctrl+shift+r"], "command": "insert_numbered_reference", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["ctrl+alt+l"], "command": "list_markdown_references", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["ctrl+alt+g"], "command": "goto_reference", "context": + { "keys": ["ctrl+alt+g"], "command": "reference_jump", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] @@ -626,17 +576,12 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["ctrl+shift+6"], "command": "magic_footnotes", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["alt+shift+6"], "command": "insert_footnote", "context": + { "keys": ["alt+shift+6"], "command": "reference_new_footnote", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["ctrl+alt+s"], "command": "sort_footnotes", "context": + { "keys": ["ctrl+alt+s"], "command": "reference_organize", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index 3c393f6d..97d149bd 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -379,16 +379,6 @@ { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, - { "keys": ["alt+shift+g"], "command": "gather_missing_link_markers", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["alt+shift+f"], "command": "gather_missing_footnotes", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, { "keys": ["tab"], "command": "complete_underlined_header", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, @@ -399,39 +389,9 @@ ] }, - // inline link insertion - { "keys": ["super+alt+k"], "command": "insert_snippet", "args": {"contents": "[$1]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|$)", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['a-zA-Z0-9_]$", "match_all": true }, - { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.single", "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["super+alt+k"], "command": "insert_snippet", "args": {"contents": "[$SELECTION]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, // inline image insertion - { "keys": ["super+shift+k"], "command": "insert_snippet", "args": {"contents": "![$1]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|$)", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['a-zA-Z0-9_]$", "match_all": true }, - { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.single", "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["super+shift+k"], "command": "insert_snippet", "args": {"contents": "![$SELECTION]($0)"}, "context": + { "keys": ["super+shift+k"], "command": "reference_new_inline_image", "context": [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, @@ -444,27 +404,17 @@ ] }, // run paste as link command on selected text - { "keys": ["super+alt+v"], "command": "paste_as_link", "context": + { "keys": ["super+alt+v"], "command": "reference_new_inline_link", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["super+alt+r"], "command": "paste_as_reference", "context": + { "keys": ["super+alt+r"], "command": "reference_new_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["super+ctrl+shift+r"], "command": "insert_numbered_reference", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["super+ctrl+alt+l"], "command": "list_markdown_references", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["super+ctrl+shift+l"], "command": "goto_reference", "context": + { "keys": ["super+ctrl+shift+l"], "command": "reference_jump", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] @@ -626,17 +576,12 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["super+shift+6"], "command": "magic_footnotes", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["alt+shift+6"], "command": "insert_footnote", "context": + { "keys": ["alt+shift+6"], "command": "reference_new_footnote", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["super+ctrl+s"], "command": "sort_footnotes", "context": + { "keys": ["super+ctrl+s"], "command": "reference_organize", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index a3fa5afe..c38f208f 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -379,16 +379,6 @@ { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, - { "keys": ["alt+shift+g"], "command": "gather_missing_link_markers", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["alt+shift+f"], "command": "gather_missing_footnotes", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, { "keys": ["tab"], "command": "complete_underlined_header", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, @@ -399,39 +389,9 @@ ] }, - // inline link insertion - { "keys": ["ctrl+super+k"], "command": "insert_snippet", "args": {"contents": "[$1]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|$)", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['a-zA-Z0-9_]$", "match_all": true }, - { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.single", "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["ctrl+super+k"], "command": "insert_snippet", "args": {"contents": "[$SELECTION]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, // inline image insertion - { "keys": ["super+shift+k"], "command": "insert_snippet", "args": {"contents": "![$1]($0)"}, "context": - [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|$)", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['a-zA-Z0-9_]$", "match_all": true }, - { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.single", "match_all": true }, - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["super+shift+k"], "command": "insert_snippet", "args": {"contents": "![$SELECTION]($0)"}, "context": + { "keys": ["super+shift+k"], "command": "reference_new_inline_image", "context": [ - { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, - { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, @@ -444,27 +404,17 @@ ] }, // run paste as link command on selected text - { "keys": ["ctrl+super+v"], "command": "paste_as_link", "context": + { "keys": ["ctrl+super+v"], "command": "reference_new_inline_link", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["ctrl+super+r"], "command": "paste_as_reference", "context": + { "keys": ["ctrl+super+r"], "command": "reference_new_reference", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["super+ctrl+shift+r"], "command": "insert_numbered_reference", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["ctrl+alt+l"], "command": "list_markdown_references", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["ctrl+alt+g"], "command": "goto_reference", "context": + { "keys": ["ctrl+alt+g"], "command": "reference_jump", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] @@ -626,17 +576,12 @@ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["ctrl+shift+6"], "command": "magic_footnotes", "context": - [ - { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } - ] - }, - { "keys": ["alt+shift+6"], "command": "insert_footnote", "context": + { "keys": ["alt+shift+6"], "command": "reference_new_footnote", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, - { "keys": ["ctrl+alt+s"], "command": "sort_footnotes", "context": + { "keys": ["ctrl+alt+s"], "command": "reference_organize", "context": [ { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] diff --git a/Default.sublime-commands b/Default.sublime-commands index 357f6bb5..4e037bb4 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -34,39 +34,43 @@ "command": "switch_list_bullet_type" }, { - "caption": "MarkdownEditing: Paste as Link", - "command": "paste_as_link" + "caption": "MarkdownEditing: Magic Footnotes Command", + "command": "magic_footnotes" }, { - "caption": "MarkdownEditing: Paste as Reference", - "command": "paste_as_reference" + "caption": "MarkdownEditing: Gather Missing Footnotes", + "command": "gather_missing_footnotes" }, { - "caption": "MarkdownEditing: Insert Named Reference...", - "command": "insert_named_reference" + "caption": "MarkdownEditing: Jump Reference", + "command": "reference_jump" }, { - "caption": "MarkdownEditing: Insert Numbered Reference...", - "command": "insert_numbered_reference" + "caption": "MarkdownEditing: New Reference", + "command": "reference_new_reference" }, { - "caption": "MarkdownEditing: Paste as Inline Link", - "command": "paste_as_inline_link" + "caption": "MarkdownEditing: New Inline Link", + "command": "reference_new_inline_link" }, { - "caption": "MarkdownEditing: Paste as Inline Image", - "command": "paste_as_inline_image" + "caption": "MarkdownEditing: New Inline Image", + "command": "reference_new_inline_image" }, { - "caption": "MarkdownEditing: Paste as Image", - "command": "paste_as_image" + "caption": "MarkdownEditing: New Image", + "command": "reference_new_image" }, { - "caption": "MarkdownEditing: Magic Footnotes Command", - "command": "magic_footnotes" + "caption": "MarkdownEditing: New Footnote", + "command": "reference_new_footnote" }, { - "caption": "MarkdownEditing: Gather Missing Footnotes", - "command": "gather_missing_footnotes" + "caption": "MarkdownEditing: Delete Reference", + "command": "reference_delete_reference" + }, + { + "caption": "MarkdownEditing: Organize References", + "command": "reference_organize" } ] diff --git a/Markdown (Standard).tmLanguage b/Markdown (Standard).tmLanguage index a51a70a4..83be4ae7 100644 --- a/Markdown (Standard).tmLanguage +++ b/Markdown (Standard).tmLanguage @@ -156,7 +156,7 @@ 1 name - punctuation.definition.constant.markdown + punctuation.definition.constant.begin.markdown 10 @@ -186,7 +186,7 @@ 3 name - punctuation.definition.constant.markdown + punctuation.definition.constant.end.markdown 4 @@ -808,7 +808,7 @@ 4 name - punctuation.definition.string.begin.markdown + punctuation.definition.string.end.markdown 5 diff --git a/Markdown.tmLanguage b/Markdown.tmLanguage index 8f7dbeea..f6c769a1 100644 --- a/Markdown.tmLanguage +++ b/Markdown.tmLanguage @@ -178,7 +178,7 @@ 1 name - punctuation.definition.constant.markdown + punctuation.definition.constant.begin.markdown 10 @@ -208,7 +208,7 @@ 3 name - punctuation.definition.constant.markdown + punctuation.definition.constant.end.markdown 4 @@ -556,6 +556,10 @@ include #link-ref + + include + #link-footnote + bold @@ -691,6 +695,10 @@ include #link-ref + + include + #link-footnote + strikethrough @@ -825,6 +833,10 @@ include #link-ref + + include + #link-footnote + bracket @@ -988,7 +1000,7 @@ 4 name - punctuation.definition.string.begin.markdown + punctuation.definition.string.end.markdown 5 @@ -1079,6 +1091,10 @@ include #link-ref + + include + #link-footnote + include #tag-kbd @@ -1219,6 +1235,10 @@ include #link-ref + + include + #link-footnote + line-break @@ -1376,6 +1396,31 @@ name meta.link.inline.markdown + link-footnote + + captures + + 1 + + name + punctuation.definition.constant.begin.markdown + + 2 + + name + constant.other.reference.link.markdown + + 3 + + name + punctuation.definition.constant.end.markdown + + + match + (\[)(\^[^\]]*+)(\]) + name + meta.link.reference.markdown + link-ref captures diff --git a/MarkdownEditor-Dark.tmTheme b/MarkdownEditor-Dark.tmTheme index f35a0f41..87e6931a 100644 --- a/MarkdownEditor-Dark.tmTheme +++ b/MarkdownEditor-Dark.tmTheme @@ -603,7 +603,7 @@ name Markup: Underline scope - markup.underline,markup.underline.link.markdown,constant.other.reference.link.markdown,meta.image.reference.markdown + markup.underline,markup.underline.link.markdown,constant.other.reference.link.markdown,meta.image.reference.markdown,meta.image.inline.markdown settings background diff --git a/MarkdownEditor-Focus.tmTheme b/MarkdownEditor-Focus.tmTheme index 11a7b5b1..f62335e4 100644 --- a/MarkdownEditor-Focus.tmTheme +++ b/MarkdownEditor-Focus.tmTheme @@ -713,7 +713,7 @@ name Markup: Underline scope - markup.underline,markup.underline.link.markdown,constant.other.reference.link.markdown,meta.image.reference.markdown + markup.underline,markup.underline.link.markdown,constant.other.reference.link.markdown,meta.image.reference.markdown,meta.image.inline.markdown settings background diff --git a/MarkdownEditor-Yellow.tmTheme b/MarkdownEditor-Yellow.tmTheme index 4707d76c..428e5ae0 100644 --- a/MarkdownEditor-Yellow.tmTheme +++ b/MarkdownEditor-Yellow.tmTheme @@ -603,7 +603,7 @@ name Markup: Underline scope - markup.underline,markup.underline.link.markdown,constant.other.reference.link.markdown,meta.image.reference.markdown + markup.underline,markup.underline.link.markdown,constant.other.reference.link.markdown,meta.image.reference.markdown,meta.image.inline.markdown settings background diff --git a/MarkdownEditor.tmTheme b/MarkdownEditor.tmTheme index a71dc710..dd32e761 100644 --- a/MarkdownEditor.tmTheme +++ b/MarkdownEditor.tmTheme @@ -603,7 +603,7 @@ name Markup: Underline scope - markup.underline,markup.underline.link.markdown,constant.other.reference.link.markdown,meta.image.reference.markdown + markup.underline,markup.underline.link.markdown,constant.other.reference.link.markdown,meta.image.reference.markdown,meta.image.inline.markdown settings background diff --git a/README.md b/README.md index 1d3b9083..b262c201 100644 --- a/README.md +++ b/README.md @@ -48,15 +48,13 @@ Markdown plugin for Sublime Text. Provides a decent Markdown color scheme (light | OS X | Windows/Linux | Description | |------|---------------|-------------| -| V | CtrlWinV | Pastes the contents of the clipboard as an inline link on selected text. -| R | CtrlWinR | Pastes the contents of the clipboard as a reference link. -| K | CtrlWinK | Inserts a standard inline link. -| K | ShiftWinK | Inserts an inline image. +| V | CtrlWinV | Creates or pastes the contents of the clipboard as an inline link on selected text. +| R | CtrlWinR | Creates or pastes the contents of the clipboard as a reference link. +| K | ShiftWinK | Creates or pastes the contents of the clipboard as an inline image on selected text. | B I | CtrlShiftB CtrlShiftI | These are bound to bold and italic. They work both with and without selections. If there is no selection, they will just transform the word under the cursor. These keybindings will unbold/unitalicize selection if it is already bold/italic. | ^1...6 | Ctrl1...6 | These will add the corresponding number of hashmarks for headlines. Works on blank lines and selected text in tandem with the above headline tools. If you select an entire existing headline, the current hashmarks will be removed and replaced with the header level you requested. This command respects the `mde.match_header_hashes` preference setting. -| 6 | CtrlShift6 | Inserts a footnote and jump to its definition. If your cursor is in a definition, it will jump back to the marker. -| F | AltShiftF | Locates footnote markers without definitions and inserts their markers for the definition. -| G | AltShiftG | Locates link references without definitions and inserts their labels at the bottom for the definition. +| 6 | AltShift6 | Inserts a footnote. +| ^S | CtrlAltS | Organizes references and footnotes. ## GFM Specific Features diff --git a/footnotes.py b/footnotes.py index 2e43e85b..d2621954 100644 --- a/footnotes.py +++ b/footnotes.py @@ -109,7 +109,7 @@ def run(self, edit): targetloc = 0 view.insert(edit, targetloc, markernum_str) if len(view.sel()) > 0: - view.insert(edit, view.size(), '\n ' + markernum_str + ': ') + view.insert(edit, view.size(), '\n' + markernum_str + ': ') view.sel().clear() view.sel().add(sublime.Region(view.size(), view.size())) view.run_command('set_motion', {"inclusive": True, "motion": "move_to", "motion_args": {"extend": True, "to": "eof"}}) diff --git a/gather_missing_links.py b/gather_missing_links.py deleted file mode 100644 index 4998c112..00000000 --- a/gather_missing_links.py +++ /dev/null @@ -1,24 +0,0 @@ -import re -import sublime_plugin - - -class GatherMissingLinkMarkersCommand(sublime_plugin.TextCommand): - def run(self, edit): - markers = [] - self.view.find_all("\]\[([^\]]+)\]", 0, "$1", markers) - self.view.find_all("\[([^\]]*)\]\[\]", 0, "$1", markers) - missinglinks = [link for link in set(markers) if not self.view.find_all("\n\s*\[%s\]:" % re.escape(link))] - if len(missinglinks): - # Remove all whitespace at the end of the file - whitespace_at_end = self.view.find(r'\s*\z', 0) - self.view.replace(edit, whitespace_at_end, "\n") - - # If there is not already a reference list at the and, insert a new line at the end - if not self.view.find(r'\n\s*\[[^\]]*\]:.*\s*\z', 0): - self.view.insert(edit, self.view.size(), "\n") - - for link in missinglinks: - self.view.insert(edit, self.view.size(), '[%s]: \n' % link) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) diff --git a/insert_references.py b/insert_references.py deleted file mode 100644 index 3ff3f6f9..00000000 --- a/insert_references.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: UTF-8 -*- - -import sublime -import sublime_plugin -import re - - -def get_clipboard_if_url(): - # If the clipboard contains an URL, return it - # Otherwise, return an empty string - re_match_urls = re.compile(r"""((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.‌​][a-z]{2,4}/)(?:[^\s()<>]+|(([^\s()<>]+|(([^\s()<>]+)))*))+(?:(([^\s()<>]+|(‌​([^\s()<>]+)))*)|[^\s`!()[]{};:'".,<>?«»“”‘’]))""", re.DOTALL) - m = re_match_urls.search(sublime.get_clipboard()) - return m.group() if m else '' - - -def mangle_url(url): - url = url.strip() - if re.match(r'^([a-z0-9-]+\.)+\w{2,4}', url, re.IGNORECASE): - url = 'http://' + url - return url - - -def check_for_link(view, url): - titles = [] - # Check if URL is already present as reference link - view.find_all(r'^\s{0,3}\[([^^\]]+)\]:[ \t]+' + re.escape(url) + '$', 0, '$1', titles) - return titles[0] if titles else None - -class AppendReferenceLinkCommand(sublime_plugin.TextCommand): - def run(self, edit, title, url): - view = self.view - # Detect if file ends with \n - if view.substr(view.size() - 1) == '\n': - nl = '' - else: - nl = '\n' - # Append the new reference link to the end of the file - view.insert(edit, view.size(), '{0}[{1}]: {2}\n'.format(nl, title, url)) - InsertReferencesCommand.run(self, edit, title) - -def append_reference_link(view, title, url): - view.run_command("append_reference_link", {"title": title, "url": url}) - -class InsertReferencesCommand(sublime_plugin.TextCommand): - def run(self, edit, title): - view = self.view - # Add a reference with given title at the current cursor or around the current selection(s) - sels = view.sel() - caret = [] - - for sel in sels: - text = view.substr(sel) - # If something is selected... - if len(text) > 0: - # ... turn the selected text into the link text - view.replace(edit, sel, "[{0}][{1}]".format(text, title)) - else: - # Add the link, with empty link text, and the caret positioned - # ready to type the link text - view.replace(edit, sel, "[][{0}]".format(title)) - caret += [sublime.Region(sel.begin() + 1, sel.begin() + 1)] - - if len(caret) > 0: - sels.clear() - for c in caret: - sels.add(c) - -def insert_references(view, title): - view.run_command("insert_references", {"title": title}) - -# Inspired by http://www.leancrew.com/all-this/2012/08/markdown-reference-links-in-bbedit/ -# Appends a new reference link to end of document, using an autoincrementing number as the reference title. -# Then inserts a reference to the link at the current selection(s). - -class InsertNumberedReferenceCommand(sublime_plugin.TextCommand): - - def description(self): - return 'Insert Numbered Reference Link' - - def run(self, edit): - self.view.window().show_input_panel( - 'URL to link to:', - get_clipboard_if_url(), - self.insert_link, - None, None) - - def insert_link(self, linkurl): - linkurl = mangle_url(linkurl) - newref = check_for_link(self.view, linkurl) - if not newref: - # Find the next reference number - reflinks = self.view.find_all(r'(?<=^\[)(\d+)(?=\]: )') - if len(reflinks) == 0: - newref = 1 - else: - newref = max(int(self.view.substr(reg)) for reg in reflinks) + 1 - - append_reference_link(self.view, newref, linkurl) - else: - insert_references(self.view, newref) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) diff --git a/jumpToMarker.py b/jumpToMarker.py deleted file mode 100644 index 738a1875..00000000 --- a/jumpToMarker.py +++ /dev/null @@ -1,26 +0,0 @@ -# Author: Gabriel Weatherhead -# Contact: gabe@macdrifter.com - -import sublime, sublime_plugin, re - -class GotoReferenceCommand(sublime_plugin.TextCommand): - def run(self, edit): - self.linkRef = [] - self.view.find_all("(^\s{0,3}\\[.*?\\]:) (.*)", 0, "$1 $2", self.linkRef) - self.view.window().show_quick_panel(self.linkRef, self.jump_to_link, sublime.MONOSPACE_FONT) - - def jump_to_link(self, choice): - if choice == -1: - return - # Set a bookmark so we can easily jump back - self.view.run_command('toggle_bookmark') - findmarker = self.linkRef[choice].split(':', 1)[1].strip() - if len(findmarker) == 0: - findmarker = self.linkRef[choice].split(':', 1)[0].strip() - self.view.sel().clear() - # Get the selection - pt = self.view.find(re.escape(findmarker+':'), 0) - self.view.sel().add(pt) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) diff --git a/list_markdown_references.py b/list_markdown_references.py deleted file mode 100644 index e84abf4b..00000000 --- a/list_markdown_references.py +++ /dev/null @@ -1,50 +0,0 @@ -import sublime, sublime_plugin -import re - - -# Based on http://www.macdrifter.com/2012/08/making-a-sublime-text-plugin-markdown-reference-viewer.html -# and http://www.leancrew.com/all-this/2012/08/more-markdown-reference-links-in-bbedit/ -# Displays a list of reference links in the document, and -# inserts a reference to the chosen item at the current selection. - -class ListMarkdownReferencesCommand(sublime_plugin.TextCommand): - def run(self, edit): - self.markers = [] - self.view.find_all(r'^\s{0,3}(\[[^^\]]+\]):[ \t]+(.+)$', 0, '$1: $2', self.markers) - self.view.window().show_quick_panel(self.markers, self.insert_link, sublime.MONOSPACE_FONT) - - def insert_link(self, choice): - if choice == -1: - return - edit = self.view.begin_edit() - - try: - # Extract the reference name that was selected - ref = re.match(r'^\[([^^\]]+)\]', self.markers[choice]).group(1) - - # Now, add a reference to that link at the current cursor or around the current selection(s) - sels = self.view.sel() - caret = [] - - for sel in sels: - text = self.view.substr(sel) - # If something is selected... - if len(text) > 0: - # ... turn the selected text into the link text - self.view.replace(edit, sel, "[{0}][{1}]".format(text, ref)) - else: - # Add the link, with empty link text, and the caret positioned - # ready to type the link text - self.view.replace(edit, sel, "[][{0}]".format(ref)) - caret += [sublime.Region(sel.begin() + 1, sel.begin() + 1)] - - if len(caret) > 0: - sels.clear() - for c in caret: - sels.add(c) - - finally: - self.view.end_edit(edit) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) diff --git a/mdeutils.py b/mdeutils.py new file mode 100644 index 00000000..71a2f8f2 --- /dev/null +++ b/mdeutils.py @@ -0,0 +1,12 @@ +import sublime +import sublime_plugin + +def view_is_markdown(view): + if len(view.sel()) > 0: + return bool(view.score_selector(view.sel()[0].a, "text.html.markdown")) + else: + return False + +class MDETextCommand(sublime_plugin.TextCommand): + def is_enabled(self): + return view_is_markdown(self.view) \ No newline at end of file diff --git a/paste_as_link.py b/paste_as_link.py deleted file mode 100644 index 91304cf4..00000000 --- a/paste_as_link.py +++ /dev/null @@ -1,13 +0,0 @@ -import sublime -import sublime_plugin - - -class PasteAsLinkCommand(sublime_plugin.TextCommand): - - def run(self, edit): - view = self.view - contents = "[${1:$SELECTION}](${2:%s})" % sublime.get_clipboard() - view.run_command("insert_snippet", {"contents": contents}) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) diff --git a/paste_as_reference.py b/paste_as_reference.py deleted file mode 100644 index f27331e6..00000000 --- a/paste_as_reference.py +++ /dev/null @@ -1,115 +0,0 @@ -import sublime -import sublime_plugin -import re - -def append_reference_link(edit, view, title, url): - # Detect if file ends with \n - if view.substr(view.size() - 1) == '\n': - nl = '' - else: - nl = '\n' - # Append the new reference link to the end of the file - edit_position = view.size() + len(nl) + 1 - view.insert(edit, view.size(), '{0}[{1}]: {2}\n'.format(nl, title, url)) - return sublime.Region(edit_position, edit_position + len(title)) - -def suggest_default_link_name(title, image): - # Camel case impl. - ret = '' - title_segs = title.split() - if len(title_segs) > 1: - for word in title_segs: - ret += word.capitalize() - if len(ret) > 30: - break - return ('image' if image else 'link') + ret - else: - return title - -def is_url(contents): - # If the clipboard contains an URL, return it - # Otherwise, return an empty string - re_match_urls = re.compile(r"""((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.‌​][a-z]{2,4}/)(?:[^\s()<>]+|(([^\s()<>]+|(([^\s()<>]+)))*))+(?:(([^\s()<>]+|(‌​([^\s()<>]+)))*)|[^\s`!()[]{};:'".,<>?«»“”‘’]))""", re.DOTALL) - m = re_match_urls.search(contents) - return True if m else False - -def mangle_url(url): - url = url.strip() - if re.match(r'^([a-z0-9-]+\.)+\w{2,4}', url, re.IGNORECASE): - url = 'http://' + url - return url - -def check_for_link(view, url): - titles = [] - # Check if URL is already present as reference link - view.find_all(r'^\s{0,3}\[([^^\]]+)\]:[ \t]+' + re.escape(url) + '$', 0, '$1', titles) - return titles[0] if titles else None - -class PasteAsReferenceCommand(sublime_plugin.TextCommand): - def run(self, edit, image = False): - view = self.view - edit_regions = [] - contents = sublime.get_clipboard().strip() - link = mangle_url(contents) if is_url(contents) else "" - suggested_title = "" - if len(link) > 0: - # If link already exists, reuse existing reference - suggested_link_name = suggested_title = check_for_link(view, link) - for sel in view.sel(): - text = view.substr(sel) - if not suggested_title: - suggested_link_name = suggest_default_link_name(text, image) - suggested_title = suggested_link_name if suggested_link_name != text else "" - edit_position = sel.end() + 3 - if image: - edit_position += 1 - self.view.replace(edit, sel, "![" + text + "][" + suggested_title + "]") - else: - self.view.replace(edit, sel, "[" + text + "][" + suggested_title + "]") - edit_regions.append(sublime.Region(edit_position, edit_position + len(suggested_title))) - if len(edit_regions) > 0: - selection = view.sel() - selection.clear() - reference_region = append_reference_link(edit, view, suggested_link_name, link) - selection.add(reference_region) - selection.add_all(edit_regions) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) - -class PasteAsInlineLinkCommand(sublime_plugin.TextCommand): - def run(self, edit, image = False): - view = self.view - edit_regions = [] - suggested_title = False - contents = sublime.get_clipboard().strip() - link = mangle_url(contents) if is_url(contents) else "" - for sel in view.sel(): - text = view.substr(sel) - edit_position = sel.end() + 3 - if image: - edit_position += 1 - self.view.replace(edit, sel, "![" + text + "](" + link + ")") - else: - self.view.replace(edit, sel, "[" + text + "](" + link + ")") - edit_regions.append(sublime.Region(edit_position, edit_position + len(link))) - if len(edit_regions) > 0: - selection.clear() - selection.add_all(edit_regions) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) - -class PasteAsInlineImage(sublime_plugin.TextCommand): - def run(self, edit): - self.view.run_command("paste_as_inline_link", {"image": True}) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) - -class PasteAsImage(sublime_plugin.TextCommand): - def run(self, edit): - self.view.run_command("paste_as_reference", {"image": True}) - - def is_enabled(self): - return bool(self.view.score_selector(self.view.sel()[0].a, "text.html.markdown")) \ No newline at end of file diff --git a/references.py b/references.py new file mode 100644 index 00000000..440210f1 --- /dev/null +++ b/references.py @@ -0,0 +1,469 @@ +import sublime +import sublime_plugin +import re +from MarkdownEditing.mdeutils import * + +refname_scope_name = "constant.other.reference.link.markdown" +definition_scope_name = "meta.link.reference.def.markdown" +marker_scope_name = "meta.link.reference.markdown" +marker_image_scope_name = "meta.image.reference.markdown" +ref_link_scope_name = "markup.underline.link.markdown" +marker_begin_scope_name = "punctuation.definition.string.begin.markdown" +marker_text_end_scope_name = "punctuation.definition.string.end.markdown" +marker_text_scope_name = "string.other.link.title.markdown" +refname_start_scope_name = "punctuation.definition.constant.begin.markdown" +marker_end_scope_name = "punctuation.definition.constant.end.markdown" + + +def hasScope(scope_name, to_find): + return to_find in scope_name.split(" ") + + +def getMarkers(view, name=''): + # returns {name -> Region} + markers = [] + name = re.escape(name) + if name == '': + markers.extend(view.find_all(r"(?<=\]\[)([^\]]+)(?=\])", 0)) # ][???] + markers.extend(view.find_all(r"(?<=\[)([^\]]*)(?=\]\[\])", 0)) # [???][] + markers.extend(view.find_all(r"(?<=\[)(\^[^\]]+)(?=\])", 0)) # [^???] + else: + # ][name] + markers.extend(view.find_all(r"(?<=\]\[)(%s)(?=\])" % name, 0)) + markers.extend(view.find_all(r"(?<=\[)(%s)(?=\]\[\])" % name, 0)) # [name][] + if name[0] == '^': + # [(^)name] + markers.extend(view.find_all(r"(?<=\[)(%s)(?=\])" % name, 0)) + regions = [] + for x in markers: + scope_name = view.scope_name(x.begin()) + if (hasScope(scope_name, refname_scope_name) or hasScope(scope_name, marker_text_scope_name)) and \ + not hasScope(view.scope_name(x.begin()), definition_scope_name): + regions.append(x) + ids = {} + for reg in regions: + name = view.substr(reg).strip() + if name in ids: + ids[name].append(reg) + else: + ids[name] = [reg] + return ids + + +def getReferences(view, name=''): + # returns {name -> Region} + refs = [] + name = re.escape(name) + if name == '': + refs.extend(view.find_all(r"(?<=^\[)([^\]]+)(?=\]:)", 0)) + else: + refs.extend(view.find_all(r"(?<=^\[)(%s)(?=\]:)" % name, 0)) + regions = refs + ids = {} + for reg in regions: + name = view.substr(reg).strip() + if name in ids: + ids[name].append(reg) + else: + ids[name] = [reg] + return ids + + +def isMarkerDefined(view, name): + # returns bool + return len(getReferences(view, name)) > 0 + + +def getCurrentScopeRegion(view, pt): + # returns Region + scope = view.scope_name(pt) + l = pt + while l > 0 and view.scope_name(l-1) == scope: + l -= 1 + r = pt + while r < view.size() and view.scope_name(r) == scope: + r += 1 + return sublime.Region(l, r) + + +def findScopeFrom(view, pt, scope, backwards=False): + # returns number + if backwards: + while pt >= 0 and not hasScope(view.scope_name(pt), scope): + pt -= 1 + else: + while pt < view.size() and not hasScope(view.scope_name(pt), scope): + pt += 1 + return pt + + +class ReferenceJumpCommand(MDETextCommand): + # reference_jump command + + def run(self, edit): + view = self.view + edit_regions = [] + markers = getMarkers(view) + refs = getReferences(view) + missingMarkers = [] + missingRefs = [] + for sel in view.sel(): + scope = view.scope_name(sel.begin()).split(" ") + if definition_scope_name in scope: + if refname_scope_name in scope: + # Definition name + defname = view.substr(getCurrentScopeRegion(view, sel.begin())) + elif refname_start_scope_name in scope: + # Starting "[" + defname = view.substr(getCurrentScopeRegion(view, sel.begin()+1)) + else: + # URL + marker_pt = findScopeFrom(view, sel.begin(), refname_scope_name, True) + defname = view.substr(getCurrentScopeRegion(view, marker_pt)) + if defname in markers: + edit_regions.extend(markers[defname]) + else: + missingMarkers.append(defname) + elif marker_scope_name in scope or marker_image_scope_name in scope: + if refname_scope_name in scope: + # defname name + defname = view.substr(getCurrentScopeRegion(view, sel.begin())) + else: + # Text + marker_pt = findScopeFrom(view, sel.begin(), refname_scope_name) + defname = view.substr(getCurrentScopeRegion(view, marker_pt)) + if defname in refs: + edit_regions.extend(refs[defname]) + else: + missingRefs.append(defname) + if len(edit_regions) > 0: + sels = view.sel() + sels.clear() + sels.add_all(edit_regions) + if len(missingRefs) + len(missingMarkers) > 0: + # has something missing + if len(missingMarkers) == 0: + sublime.status_message("The definition%s of %s cannot be found." % + ("" if len(missingRefs) == 1 else "s", ", ".join(missingRefs))) + elif len(missingRefs) == 0: + sublime.status_message("The marker%s of %s cannot be found." % + ("" if len(missingMarkers) == 1 else "s", ", ".join(missingMarkers))) + else: + sublime.status_message("The definition%s of %s and the marker%s of %s cannot be found." % + ("" if len(missingRefs) == 1 else "s", ", ".join(missingRefs), + "" if len(missingMarkers) == 1 else "s", ", ".join(missingMarkers))) + + +def is_url(contents): + # Returns if contents contains an URL + re_match_urls = re.compile(r"""((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.‌​][a-z]{2,4}/)(?:[^\s()<>]+|(([^\s()<>]+|(([^\s()<>]+)))*))+(?:(([^\s()<>]+|(‌​([^\s()<>]+)))*)|[^\s`!()[]{};:'".,<>?«»“”‘’]))""", re.DOTALL) + m = re_match_urls.search(contents) + return True if m else False + + +def mangle_url(url): + url = url.strip() + if re.match(r'^([a-z0-9-]+\.)+\w{2,4}', url, re.IGNORECASE): + url = 'http://' + url + return url + + +def append_reference_link(edit, view, name, url): + # Detect if file ends with \n + if view.substr(view.size() - 1) == '\n': + nl = '' + else: + nl = '\n' + # Append the new reference link to the end of the file + edit_position = view.size() + len(nl) + 1 + view.insert(edit, view.size(), '{0}[{1}]: {2}\n'.format(nl, name, url)) + return sublime.Region(edit_position, edit_position + len(name)) + + +def suggest_default_link_name(name, image): + # Camel case impl. + ret = '' + name_segs = name.split() + if len(name_segs) > 1: + for word in name_segs: + ret += word.capitalize() + if len(ret) > 30: + break + return ('image' if image else 'link') + ret + else: + return name + + +def check_for_link(view, link): + refs = getReferences(view) + link = link.strip() + for name in refs: + link_begin = findScopeFrom(view, refs[name][0].begin(), ref_link_scope_name) + reg = getCurrentScopeRegion(view, link_begin) + found_link = view.substr(reg).strip() + if found_link == link: + return name + return None + + +class ReferenceNewReferenceCommand(MDETextCommand): + # reference_new_reference command + + def run(self, edit, image=False): + view = self.view + edit_regions = [] + contents = sublime.get_clipboard().strip() + link = mangle_url(contents) if is_url(contents) else "" + suggested_name = "" + if len(link) > 0: + # If link already exists, reuse existing reference + suggested_link_name = suggested_name = check_for_link(view, link) + for sel in view.sel(): + text = view.substr(sel) + if not suggested_name: + suggested_link_name = suggest_default_link_name(text, image) + suggested_name = suggested_link_name if suggested_link_name != text else "" + edit_position = sel.end() + 3 + if image: + edit_position += 1 + view.replace(edit, sel, "![" + text + "][" + suggested_name + "]") + else: + view.replace(edit, sel, "[" + text + "][" + suggested_name + "]") + edit_regions.append(sublime.Region(edit_position, edit_position + len(suggested_name))) + if len(edit_regions) > 0: + selection = view.sel() + selection.clear() + reference_region = append_reference_link(edit, view, suggested_link_name, link) + selection.add(reference_region) + selection.add_all(edit_regions) + + +class ReferenceNewInlineLinkCommand(MDETextCommand): + # reference_new_inline_link command + + def run(self, edit, image=False): + view = self.view + edit_regions = [] + suggested_name = False + contents = sublime.get_clipboard().strip() + link = mangle_url(contents) if is_url(contents) else "" + for sel in view.sel(): + text = view.substr(sel) + edit_position = sel.end() + 3 + if image: + edit_position += 1 + view.replace(edit, sel, "![" + text + "](" + link + ")") + else: + view.replace(edit, sel, "[" + text + "](" + link + ")") + edit_regions.append(sublime.Region(edit_position, edit_position + len(link))) + if len(edit_regions) > 0: + selection = view.sel() + selection.clear() + selection.add_all(edit_regions) + + +class ReferenceNewInlineImage(MDETextCommand): + # reference_new_inline_image command + + def run(self, edit): + self.view.run_command("reference_new_inline_link", {"image": True}) + + +class ReferenceNewImage(MDETextCommand): + # reference_new_image command + + def run(self, edit): + self.view.run_command("reference_new_reference", {"image": True}) + + +def get_next_footnote_marker(view): + refs = getReferences(view) + footnotes = [int(ref[1:]) for ref in refs if view.substr(refs[ref][0])[0] == "^"] + + def target_loc(num): + return (num - 1) % len(footnotes) + for i in range(len(footnotes)): + footnote = footnotes[i] + tl = target_loc(footnote) + # footnotes = [1 2 {4} 5], i = 2, footnote = 4, tl = 3 + while tl != i: + target_fn = footnotes[tl] + ttl = target_loc(target_fn) + # target_fn = 5, ttl = 0 + if ttl != tl or target_fn > footnote: + footnotes[i], footnotes[tl] = footnotes[tl], footnotes[i] + tl, footnote = ttl, target_fn + # [1 2 {5} 4] + else: + break + for i in range(len(footnotes)): + if footnotes[i] != i+1: + return i+1 + return len(footnotes) + 1 + + +class ReferenceNewFootnote(MDETextCommand): + # reference_new_footnote command + + def run(self, edit): + view = self.view + markernum = get_next_footnote_marker(view) + markernum_str = '[^%s]' % markernum + for sel in view.sel(): + startloc = sel.end() + if bool(view.size()): + targetloc = view.find('(\s|$)', startloc).begin() + else: + targetloc = 0 + view.insert(edit, targetloc, markernum_str) + if len(view.sel()) > 0: + view.insert(edit, view.size(), '\n' + markernum_str + ': ') + view.sel().clear() + view.sel().add(sublime.Region(view.size(), view.size())) + + +class ReferenceDeleteReference(MDETextCommand): + # reference_delete_reference command + + def run(self, edit): + view = self.view + edit_regions = [] + markers = getMarkers(view) + refs = getReferences(view) + for sel in view.sel(): + scope = view.scope_name(sel.begin()).split(" ") + if definition_scope_name in scope: + if refname_scope_name in scope: + # Definition name + defname = view.substr(getCurrentScopeRegion(view, sel.begin())) + elif refname_start_scope_name in scope: + # Starting "[" + defname = view.substr(getCurrentScopeRegion(view, sel.begin()+1)) + else: + # URL + marker_pt = findScopeFrom(view, sel.begin(), refname_scope_name, True) + defname = view.substr(getCurrentScopeRegion(view, marker_pt)) + elif marker_scope_name in scope or marker_image_scope_name in scope: + if refname_scope_name in scope: + # defname name + defname = view.substr(getCurrentScopeRegion(view, sel.begin())) + else: + # Text + marker_pt = findScopeFrom(view, sel.begin(), refname_scope_name) + defname = view.substr(getCurrentScopeRegion(view, marker_pt)) + else: + defname = None + if defname and defname in markers: + for marker in markers[defname]: + if defname[0] == "^": + edit_regions.append(sublime.Region(marker.begin()-1, marker.end()+1)) + else: + l = findScopeFrom(view, marker.begin(), marker_begin_scope_name, True) + if l > 0 and view.substr(sublime.Region(l-1, l)) == "!": + edit_regions.append(sublime.Region(l-1, l+1)) + else: + edit_regions.append(sublime.Region(l, l+1)) + r = findScopeFrom(view, marker.begin(), marker_text_end_scope_name, True) + edit_regions.append(sublime.Region(r, marker.end()+1)) + if defname in refs: + for ref in refs[defname]: + edit_regions.append(view.full_line(ref.begin())) + + if len(edit_regions) > 0: + sel = view.sel() + sel.clear() + sel.add_all(edit_regions) + + def delete_all(index): + if index == 0: + view.run_command("left_delete") + view.window().show_quick_panel(["Delete the References", "Preview the Changes"], delete_all, sublime.MONOSPACE_FONT) + + +class ReferenceOrganize(MDETextCommand): + # reference_organize command + + def run(self, edit): + view = self.view + + # reorder + refs = getReferences(view) + flatrefs = [] + flatfns = [] + sel = view.sel() + sel.clear() + for name in refs: + for link_reg in refs[name]: + line_reg = view.full_line(link_reg) + if name[0] == "^": + flatfns.append((name, view.substr(line_reg))) + else: + flatrefs.append((name, view.substr(line_reg))) + sel.add(line_reg) + flatfns.sort(key=lambda r: r[0]) + flatrefs.sort(key=lambda r: r[0]) + view.run_command("left_delete") + if view.size() >= 2 and view.substr(sublime.Region(view.size()-2, view.size())) == "\n\n": + view.erase(edit, sublime.Region(view.size()-1, view.size())) + for fn_tuple in flatfns: + view.insert(edit, view.size(), fn_tuple[1]) + view.insert(edit, view.size(), "\n") + for ref_tuple in flatrefs: + view.insert(edit, view.size(), ref_tuple[1]) + + # delete duplicate / report conflict + sel.clear() + refs = getReferences(view) + conflicts = {} + unique_links = {} + output = "" + + for name in refs: + if name[0] == '^': + continue + n_links = len(refs[name]) + if n_links > 1: + for ref in refs[name]: + link_begin = findScopeFrom(view, ref.end(), ref_link_scope_name) + link = view.substr(getCurrentScopeRegion(view, link_begin)) + if name in unique_links: + if link == unique_links[name]: + output += "%s has duplicate value of %s\n" % (name, link) + sel.add(view.full_line(ref.begin())) + elif name in conflicts: + conflicts[name].append(link) + else: + conflicts[name] = [link] + else: + unique_links[name] = link + + # view.run_command("left_delete") + + for name in conflicts: + output += "%s has conflict values: %s with %s\n" % (name, unique_links[name], ", ".join(conflicts[name])) + + # report missing + refs = getReferences(view) + markers = getMarkers(view) + print(markers) + missings = [] + for ref in refs: + if ref not in markers: + missings.append(ref) + if len(missings) > 0: + output += "definition [%s] %s no reference\n" % (", ".join(missings), "have" if len(missings) > 1 else "has") + + missings = [] + for marker in markers: + if marker not in refs: + missings.append(marker) + if len(missings) > 0: + output += "[%s] %s no definition\n" % (", ".join(missings), "have" if len(missings) > 1 else "has") + + # sel.clear() + if len(output) > 0: + window = view.window() + output_panel = window.create_output_panel("mde") + output_panel.run_command('erase_view') + output_panel.run_command('append', {'characters': output}) + window.run_command("show_panel", {"panel": "output.mde"}) From bc57398c0a7bb6645a66564975a55e5c4dd76cfa Mon Sep 17 00:00:00 2001 From: Tristan Berger Date: Mon, 11 Jan 2016 03:12:09 -0700 Subject: [PATCH 22/23] Require HTML block closing tags be at the beginning of their line --- Markdown (Standard).tmLanguage | 2 +- Markdown.tmLanguage | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Markdown (Standard).tmLanguage b/Markdown (Standard).tmLanguage index a51a70a4..f3328c06 100644 --- a/Markdown (Standard).tmLanguage +++ b/Markdown (Standard).tmLanguage @@ -122,7 +122,7 @@ Markdown formatting is disabled inside block-level tags. end - (?<=</\1>$\n) + (?<=^</\1>$\n) patterns diff --git a/Markdown.tmLanguage b/Markdown.tmLanguage index 8f7dbeea..44d05662 100644 --- a/Markdown.tmLanguage +++ b/Markdown.tmLanguage @@ -136,7 +136,7 @@ Markdown formatting is disabled inside block-level tags. end - (?<=</\1>$\n) + (?<=^</\1>$\n) patterns From 63377e6203796996613bee465e8a98235e0a2013 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Thu, 14 Jan 2016 16:01:48 +0800 Subject: [PATCH 23/23] Mention scopes for theme contributors related to #226 --- CONTRIBUTING.md | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 24397c1b..78abaa7b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,3 +49,134 @@ Each milestone will have a pull request that will be kept open until the milesto When the milestone is completed, push-access users can publish the new version to the Package Control. Creating the new version __tag__ on the GitHub repository is enough for this. For example, if the name of the milestone is `v2.0.4`, the tag should be `2.0.4`. The update process may take __up to an hour__ depending on the crawl frequency by the Package Control. + +## Contributing to themes + +Here are the used scopes under 3 different markdown flavors. If you are not sure about how the scopes are used, checkout .tmlanguage files or ask in issues. __Unique__ scopes are marked as bold. + +### ScopeName: text.html.markdown + +* constant.character.escape.markdown +* constant.other.reference.link.markdown +* invalid.illegal.whitespace.markdown +* markup.bold.markdown +* markup.bold_italic.markdown +* markup.heading.1.markdown +* markup.heading.2.markdown +* markup.heading.markdown +* markup.italic.markdown +* markup.list.numbered.markdown +* markup.list.unnumbered.markdown +* markup.quote.markdown +* markup.raw.block.markdown +* markup.raw.inline.content.markdown +* markup.raw.inline.markdown +* markup.underline.link.image.markdown +* markup.underline.link.markdown +* meta.block-level.markdown +* meta.disable-markdown +* meta.dummy.line-break +* meta.image.inline.markdown +* meta.image.reference.markdown +* meta.link.email.lt-gt.markdown +* meta.link.inet.markdown +* meta.link.inline.markdown +* meta.link.reference.def.markdown +* meta.link.reference.literal.markdown +* meta.link.reference.markdown +* meta.other.valid-ampersand.markdown +* meta.other.valid-bracket.markdown +* meta.paragraph.list.markdown +* meta.paragraph.markdown +* meta.separator.markdown +* punctuation.definition.blockquote.markdown +* punctuation.definition.bold.markdown +* punctuation.definition.constant.begin.markdown +* punctuation.definition.constant.end.markdown +* punctuation.definition.constant.markdown +* punctuation.definition.heading.markdown +* punctuation.definition.italic.markdown +* punctuation.definition.link.markdown +* punctuation.definition.list_item.markdown +* __punctuation.definition.list_item.number.markdown__ +* punctuation.definition.metadata.markdown +* punctuation.definition.raw.markdown +* punctuation.definition.string.begin.markdown +* punctuation.definition.string.end.markdown +* punctuation.definition.string.markdown +* punctuation.separator.key-value.markdown +* string.other.link.description.markdown +* string.other.link.description.title.markdown +* string.other.link.title.markdown + +### ScopeName: text.html.markdown.gfm + +* constant.character.escape.markdown +* constant.other.reference.link.markdown +* __entity.name.tag.other.html__ +* invalid.illegal.whitespace.markdown +* markup.bold.markdown +* markup.bold_italic.markdown +* markup.heading.1.markdown +* markup.heading.2.markdown +* markup.heading.markdown +* markup.italic.markdown +* __markup.kbd.content.markdown__ +* __markup.kbd.markdown__ +* markup.list.numbered.markdown +* markup.list.unnumbered.markdown +* markup.quote.markdown +* __markup.raw.block.fenced.markdown__ +* markup.raw.block.markdown +* markup.raw.inline.content.markdown +* markup.raw.inline.markdown +* __markup.strikethrough.markdown__ +* markup.underline.link.image.markdown +* markup.underline.link.markdown +* meta.block-level.markdown +* meta.disable-markdown +* meta.dummy.line-break +* meta.image.inline.markdown +* meta.image.reference.markdown +* meta.link.email.lt-gt.markdown +* meta.link.inet.markdown +* meta.link.inline.markdown +* meta.link.reference.def.markdown +* meta.link.reference.literal.markdown +* meta.link.reference.markdown +* meta.other.valid-ampersand.markdown +* meta.other.valid-bracket.markdown +* meta.paragraph.list.markdown +* meta.paragraph.markdown +* meta.separator.markdown +* __meta.tag.other.html__ +* punctuation.definition.blockquote.markdown +* punctuation.definition.bold.markdown +* punctuation.definition.constant.begin.markdown +* punctuation.definition.constant.end.markdown +* punctuation.definition.constant.markdown +* punctuation.definition.heading.markdown +* punctuation.definition.italic.markdown +* punctuation.definition.link.markdown +* punctuation.definition.list_item.markdown +* punctuation.definition.metadata.markdown +* punctuation.definition.raw.markdown +* __punctuation.definition.strikethrough.markdown__ +* punctuation.definition.string.begin.markdown +* punctuation.definition.string.end.markdown +* punctuation.definition.string.markdown +* __punctuation.definition.tag.begin.html__ +* __punctuation.definition.tag.end.html__ +* punctuation.separator.key-value.markdown +* string.other.link.description.markdown +* string.other.link.description.title.markdown +* string.other.link.title.markdown + +### ScopeName: text.html.markdown.multimarkdown + +* +* __keyword.other.multimarkdown__ +* __punctuation.separator.key-value.multimarkdown__ +* __meta.header.multimarkdown__ +* __string.unquoted.multimarkdown__ +* __meta.content.multimarkdown__ \ No newline at end of file