Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb48b1c79f | |||
| 8317fa738c | |||
| 3be12b0539 | |||
| c92d78fb20 | |||
| 30d75f159d | |||
| 52e4b917e5 | |||
| 48a68b2a79 | |||
| 8eb0172eb4 |
@ -1,4 +1,16 @@
|
|||||||
{
|
{
|
||||||
|
// As soon as you open a markdown file, it opens the window preview
|
||||||
"markdown_live_preview_on_open": false,
|
"markdown_live_preview_on_open": false,
|
||||||
"load_from_internet_when_starts": ["http://", "https://"]
|
|
||||||
|
// If an image starts with one of those strings, then it will be loaded from internet
|
||||||
|
"load_from_internet_when_starts": ["http://", "https://"],
|
||||||
|
|
||||||
|
// When the preview is opened, the markdown file is closed in the origin window and reopend in
|
||||||
|
// the preview window. If this option is set to 'true', then the markdown file will NOT be
|
||||||
|
// closed in the origin window
|
||||||
|
"keep_open_when_opening_preview": false,
|
||||||
|
|
||||||
|
// Choose what to do with YAML/TOML (---/+++ respectively) headers
|
||||||
|
// Valid values: "wrap_in_pre", "remove".
|
||||||
|
"header_action": "wrap_in_pre"
|
||||||
}
|
}
|
||||||
|
|||||||
47
MLPApi.py
47
MLPApi.py
@ -30,13 +30,6 @@ def plugin_loaded():
|
|||||||
else:
|
else:
|
||||||
DEFAULT_STYLE_FILE = sublime.load_resource('Packages/MarkdownLivePreview/default.css')
|
DEFAULT_STYLE_FILE = sublime.load_resource('Packages/MarkdownLivePreview/default.css')
|
||||||
|
|
||||||
def get_preview_name(md_view):
|
|
||||||
file_name = md_view.file_name()
|
|
||||||
name = md_view.name() \
|
|
||||||
or os.path.basename(file_name) if file_name else None \
|
|
||||||
or 'Untitled'
|
|
||||||
return name + ' - Preview'
|
|
||||||
|
|
||||||
def create_preview(window, file_name):
|
def create_preview(window, file_name):
|
||||||
preview = window.new_file()
|
preview = window.new_file()
|
||||||
|
|
||||||
@ -55,23 +48,43 @@ def get_style():
|
|||||||
return content
|
return content
|
||||||
|
|
||||||
def markdown2html(md, basepath):
|
def markdown2html(md, basepath):
|
||||||
|
# removes/format the header.
|
||||||
|
md = manage_header(md, get_settings().get('header_action'))
|
||||||
|
|
||||||
html = '<style>\n{}\n</style>\n'.format(get_style())
|
html = '<style>\n{}\n</style>\n'.format(get_style())
|
||||||
# pre_with_br
|
|
||||||
html += pre_with_br(pre_tables(md2.markdown(md, extras=['fenced-code-blocks',
|
|
||||||
'no-code-highlighting', 'tables'])))
|
|
||||||
# the option no-code-highlighting does not exists in the official version of markdown2 for now
|
# the option no-code-highlighting does not exists in the official version of markdown2 for now
|
||||||
# I personaly edited the file (markdown2.py:1743)
|
# I personaly edited the file (markdown2.py:1743)
|
||||||
|
html += md2.markdown(md, extras=['fenced-code-blocks', 'no-code-highlighting', 'tables'])
|
||||||
|
|
||||||
|
# tables aren't supported by the Phantoms
|
||||||
|
# This function transforms them into aligned ASCII tables and displays them in a <pre> block
|
||||||
|
# (the ironic thing is that they aren't supported either :D)
|
||||||
|
html = pre_tables(html)
|
||||||
|
|
||||||
|
# pre block are not supported by the Phantoms.
|
||||||
|
# This functions replaces the \n in them with <br> so that it does (1/2)
|
||||||
|
html = pre_with_br(html)
|
||||||
|
|
||||||
|
# comments aren't supported by the Phantoms
|
||||||
|
# Simply removes them using bs4, so you can be sadic and type `<!-- hey hey! -->`, these one
|
||||||
|
# won't be stripped!
|
||||||
html = strip_html_comments(html)
|
html = strip_html_comments(html)
|
||||||
|
|
||||||
# Beautiful uses the <br/> but the sublime phantoms do not support them...
|
|
||||||
html = html.replace('<br/>', '<br />')
|
|
||||||
|
|
||||||
html = html.replace(' ', ' espace;') # save where are the spaces
|
|
||||||
|
|
||||||
# exception, again, because <pre> aren't supported by the phantoms
|
# exception, again, because <pre> aren't supported by the phantoms
|
||||||
html = html.replace(' espace;', '<i class="space">.</i>')
|
# so, because this is monosaped font, I just replace it with a '.' and make transparent ;)
|
||||||
|
html = html.replace(' ', '<i class="space">.</i>')
|
||||||
|
|
||||||
|
# Phantoms have problem with images size when they're loaded from an url/path
|
||||||
|
# So, the solution is to convert them to base64
|
||||||
html = replace_img_src_base64(html, basepath=os.path.dirname(basepath))
|
html = replace_img_src_base64(html, basepath=os.path.dirname(basepath))
|
||||||
sublime.set_clipboard(html)
|
|
||||||
|
# BeautifulSoup uses the <br/> but the sublime phantoms do not support them...
|
||||||
|
html = html.replace('<br/>', '<br />').replace('<hr/>', '<hr />')
|
||||||
|
|
||||||
|
sublime.set_clipboard(html) # print
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def show_html(md_view, preview):
|
def show_html(md_view, preview):
|
||||||
|
|||||||
@ -15,7 +15,8 @@ class NewMarkdownLivePreviewCommand(sublime_plugin.ApplicationCommand):
|
|||||||
|
|
||||||
current_view = sublime.active_window().active_view()
|
current_view = sublime.active_window().active_view()
|
||||||
file_name = current_view.file_name()
|
file_name = current_view.file_name()
|
||||||
current_view.close()
|
if get_settings().get('keep_open_when_opening_preview') is False:
|
||||||
|
current_view.close()
|
||||||
if file_name is None:
|
if file_name is None:
|
||||||
return sublime.error_message('MarkdownLivePreview: Not supporting '
|
return sublime.error_message('MarkdownLivePreview: Not supporting '
|
||||||
'unsaved file for now')
|
'unsaved file for now')
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
Fast:
|
Fast:
|
||||||
☐ cache image in object when used, so that it's faster @needsTest
|
☐ cache image in object when used, so that it's faster @needsTest
|
||||||
|
☐ add settings to keep md view open #13
|
||||||
|
|
||||||
Medium:
|
Medium:
|
||||||
☐ auto refresh preview if loading images
|
☐ auto refresh preview if loading images
|
||||||
|
|||||||
18
README.md
18
README.md
@ -35,17 +35,25 @@ Once you're done, close whichever file and it'll close the entire window.
|
|||||||
|
|
||||||
### Settings
|
### Settings
|
||||||
|
|
||||||
|
To edit MarkdownLivePreview's settings, you just need to look in the command palette
|
||||||
|
`Preferences: MarkdownLivePreview Settings`, or from the menus:
|
||||||
|
*Preferences → Package Settings → MarkdownLivePreview → Settings*
|
||||||
|
|
||||||
|
Do not edit the left file (by default, you cannot), but edit the right file. This last file will
|
||||||
|
override the default one (on the left), and will be saved in your `User` folder, which makes it easy
|
||||||
|
to back up.
|
||||||
|
|
||||||
- `markdown_live_preview_on_open`: if set to `true`, as soon as you open a markdown file, the
|
- `markdown_live_preview_on_open`: if set to `true`, as soon as you open a markdown file, the
|
||||||
preview window will popup (thanks to[@ooing](https://github.com/ooing) for its
|
preview window will popup (thanks to[@ooing](https://github.com/ooing) for its
|
||||||
[suggestion](https://github.com/math2001/MarkdownLivePreview/issues/7#issue-199464852)). Default to
|
[suggestion](https://github.com/math2001/MarkdownLivePreview/issues/7#issue-199464852)). Default to
|
||||||
`false`
|
`false`
|
||||||
- `load_from_internet_when_starts`: every images that starts with any of the string specified in
|
- `load_from_internet_when_starts`: every images that starts with any of the string specified in
|
||||||
this list will be loaded from internet. Default to `["http://", "https://"]`
|
this list will be loaded from internet. Default to `["http://", "https://"]`
|
||||||
|
- `header_action`: If you're writing a blog with some markdown and a static website generator, you
|
||||||
Note: To edit your settings, search up in the command palette
|
probably have a YAML header. By default, this header will be displayed in a `pre` block. If you want
|
||||||
`Preferences: MarkdownLivePreview Settings`, or by using the menu:
|
to hide it, then just set the value to `remove`
|
||||||
*Preferences → Packages Settings → MarkdownLivePreview → Settings*;. It's not your global settings,
|
- `keep_open_when_opening_preview`: Each time the preview window is opened, the original markdown
|
||||||
but only the `MarkdownLivePreview`'s one
|
view is closed. If you want to keep it opened, just set this setting to `true`
|
||||||
|
|
||||||
### Syntax Specific Settings
|
### Syntax Specific Settings
|
||||||
|
|
||||||
|
|||||||
62
functions.py
62
functions.py
@ -11,37 +11,47 @@ def plugin_loaded():
|
|||||||
loading = sublime.load_resource('Packages/MarkdownLivePreview/loading.txt')
|
loading = sublime.load_resource('Packages/MarkdownLivePreview/loading.txt')
|
||||||
error404 = sublime.load_resource('Packages/MarkdownLivePreview/404.txt')
|
error404 = sublime.load_resource('Packages/MarkdownLivePreview/404.txt')
|
||||||
|
|
||||||
|
MATCH_YAML_HEADER = re.compile(r'^([\-\+])\1{2}\n(?P<content>.+)\n\1{3}\n', re.DOTALL)
|
||||||
|
|
||||||
def strip_html_comments(html):
|
def strip_html_comments(html):
|
||||||
soup = BeautifulSoup(html, 'html.parser')
|
soup = BeautifulSoup(html, 'html.parser')
|
||||||
for element in soup.find_all(text=lambda text: isinstance(text, html_comment)):
|
for element in soup.find_all(text=lambda text: isinstance(text, html_comment)):
|
||||||
element.extract()
|
element.extract()
|
||||||
return str(soup)
|
return str(soup)
|
||||||
|
|
||||||
def replace_img_src_base64(html, basepath):
|
def manage_header(md, action):
|
||||||
"""Really messy, but it works (should be updated)"""
|
matchobj = MATCH_YAML_HEADER.match(md)
|
||||||
index = -1
|
if not matchobj:
|
||||||
tag_start = '<img src="'
|
return md
|
||||||
shtml, html = html, list(html)
|
if action == 'remove':
|
||||||
while True:
|
return md[len(matchobj.group(0)):]
|
||||||
index = shtml.find(tag_start, index + 1)
|
elif action == 'wrap_in_pre':
|
||||||
if index == -1:
|
return '<pre><code>' + matchobj.group('content') + '</code></pre>' \
|
||||||
break
|
+ md[len(matchobj.group(0)):]
|
||||||
path, end = get_content_till(html, '"', start=index + len(tag_start))
|
|
||||||
if ''.join(path).startswith('data:image/'):
|
|
||||||
continue
|
|
||||||
if ''.join(path).startswith(tuple(get_settings().get('load_from_internet' + \
|
|
||||||
'_when_starts', []))):
|
|
||||||
image = ImageManager.get(''.join(path))
|
|
||||||
image = image or loading
|
|
||||||
|
|
||||||
else:
|
raise ValueError('Got an unknown action: "{}"'.format(action))
|
||||||
# local image
|
|
||||||
path = ''.join(path)
|
def get_preview_name(md_view):
|
||||||
path = os.path.join(basepath, path)
|
file_name = md_view.file_name()
|
||||||
image = to_base64(path)
|
name = md_view.name() \
|
||||||
html[index+len(tag_start):end] = image
|
or os.path.basename(file_name) if file_name else None \
|
||||||
shtml = ''.join(html)
|
or 'Untitled'
|
||||||
return ''.join(html)
|
return name + ' - Preview'
|
||||||
|
|
||||||
|
def replace_img_src_base64(html, basepath):
|
||||||
|
soup = BeautifulSoup(html, 'html.parser')
|
||||||
|
load_from_internet_starters = get_settings().get('load_from_internet_when_starts')
|
||||||
|
for img in soup.find_all('img'):
|
||||||
|
if img['src'].startswith('data:image/'):
|
||||||
|
continue
|
||||||
|
elif img['src'].startswith(tuple(load_from_internet_starters)):
|
||||||
|
image = ImageManager.get(img['src']) or loading
|
||||||
|
else: # this is a local image
|
||||||
|
image = to_base64(os.path.join(basepath, src))
|
||||||
|
|
||||||
|
img['src'] = image
|
||||||
|
|
||||||
|
return str(soup)
|
||||||
|
|
||||||
def is_markdown_view(view):
|
def is_markdown_view(view):
|
||||||
return 'markdown' in view.scope_name(0)
|
return 'markdown' in view.scope_name(0)
|
||||||
@ -95,9 +105,9 @@ def get_settings():
|
|||||||
def pre_with_br(html):
|
def pre_with_br(html):
|
||||||
"""Because the phantoms of sublime text does not support <pre> blocks
|
"""Because the phantoms of sublime text does not support <pre> blocks
|
||||||
this function replaces every \n with a <br> in a <pre>"""
|
this function replaces every \n with a <br> in a <pre>"""
|
||||||
soup = BeautifulSoup(html)
|
soup = BeautifulSoup(html, 'html.parser')
|
||||||
for pre in soup.find_all('pre'):
|
for pre in soup.find_all('pre'):
|
||||||
code = pre.find('code')
|
code = pre.find('code')
|
||||||
code.replaceWith(BeautifulSoup(''.join(str(node) for node in pre.contents) \
|
code.replaceWith(BeautifulSoup(''.join(str(node) for node in pre.contents) \
|
||||||
.replace('\n', '<br/>').replace(' ', '<i class="space">.</i>'), 'html.parser'))
|
.replace('\n', '<br/>').replace(' ', '<i class="space">.</i>'), 'html.parser'))
|
||||||
return str(soup)
|
return str(soup)
|
||||||
|
|||||||
11
sample.md
11
sample.md
@ -1,7 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: Demo
|
||||||
|
description: Preview your markdown right in Sublime Text!
|
||||||
|
hope: You'll enjoy using it!
|
||||||
|
---
|
||||||
|
|
||||||
# Hello world
|
# Hello world
|
||||||
|
|
||||||
<!-- supports comments -->
|
<!-- supports comments -->
|
||||||
|
|
||||||
|
And `<!-- vicious ones ;) -->`
|
||||||
|
|
||||||
Some `inline code` with *italic* and **bold** text.
|
Some `inline code` with *italic* and **bold** text.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -18,6 +26,7 @@ if you is moods.curious:
|
|||||||
- you need
|
- you need
|
||||||
- todos
|
- todos
|
||||||
|
|
||||||
|
|
||||||
| ID | Name |
|
| ID | Name |
|
||||||
|-----------|-------|
|
|-----------|-------|
|
||||||
| 56 | Matt |
|
| 56 | Matt |
|
||||||
@ -26,7 +35,7 @@ if you is moods.curious:
|
|||||||
| 45 | John |
|
| 45 | John |
|
||||||
| `<table>` | `><` |
|
| `<table>` | `><` |
|
||||||
|
|
||||||
[Sublime Text Logo](https://upload.wikimedia.org/wikipedia/en/4/4c/Sublime_Text_Logo.png)
|

|
||||||
|
|
||||||
Some plugin I just *need*:
|
Some plugin I just *need*:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user