Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8cc6b2b263 | |||
| c7961ce94c | |||
| eae91fa428 | |||
| 6f18e8e4a2 | |||
| 48c1800065 | |||
| bad1cb74c6 | |||
| 4198504fd1 | |||
| 1bef00de14 | |||
| d707cf7a47 |
@ -7,6 +7,13 @@
|
||||
"caption": "MarkdownLivePreview: Clear the cache",
|
||||
"command": "markdown_live_preview_clear_cache"
|
||||
},
|
||||
{
|
||||
"caption": "MarkdownLivePreview: Edit Custom CSS File",
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "$packages/User/MarkdownLivePreview.css"
|
||||
}
|
||||
},
|
||||
{
|
||||
"caption": "Preferences: MarkdownLivePreview Settings",
|
||||
"command": "edit_settings",
|
||||
|
||||
48
MLPApi.py
48
MLPApi.py
@ -7,6 +7,7 @@ import os.path
|
||||
from html.parser import HTMLParser
|
||||
|
||||
from .lib import markdown2 as md2
|
||||
from .lib.pre_tables import pre_tables
|
||||
from .escape_amp import *
|
||||
from .functions import *
|
||||
from .setting_names import *
|
||||
@ -15,14 +16,18 @@ from random import randint as rnd
|
||||
|
||||
__folder__ = os.path.dirname(__file__)
|
||||
|
||||
STYLE_FILE = os.path.join(os.path.dirname(__folder__), 'User',
|
||||
'MarkdownLivePreview.css')
|
||||
USER_STYLE_FILE = os.path.join(os.path.dirname(__folder__), 'User', 'MarkdownLivePreview.css')
|
||||
|
||||
# used to store the phantom's set
|
||||
windows_phantom_set = {}
|
||||
|
||||
|
||||
def plugin_loaded():
|
||||
global DEFAULT_STYLE_FILE
|
||||
if os.path.exists(os.path.join(__folder__, 'default.css')):
|
||||
with open(os.path.join(__folder__, 'default.css')) as fp:
|
||||
DEFAULT_STYLE_FILE = fp.read()
|
||||
else:
|
||||
DEFAULT_STYLE_FILE = sublime.load_resource('Packages/MarkdownLivePreview/default.css')
|
||||
|
||||
def get_preview_name(md_view):
|
||||
@ -44,37 +49,36 @@ def create_preview(window, file_name):
|
||||
|
||||
def get_style():
|
||||
content = ''.join([line.strip() + ' ' for line in DEFAULT_STYLE_FILE.splitlines()])
|
||||
return content + "pre code .space {color: var(--light-bg)}"
|
||||
if os.path.exists(USER_STYLE_FILE):
|
||||
with open(USER_STYLE_FILE) as fp:
|
||||
content += '\n' + fp.read() + '\n'
|
||||
return content
|
||||
|
||||
def show_html(md_view, preview):
|
||||
global windows_phantom_set
|
||||
html = []
|
||||
html.append('<style>\n{}\n</style>'.format(get_style()))
|
||||
html.append(pre_with_br(md2.markdown(get_view_content(md_view),
|
||||
extras=['fenced-code-blocks',
|
||||
'no-code-highlighting'])))
|
||||
# the option no-code-highlighting does not exists
|
||||
# in the official version of markdown2 for now
|
||||
def markdown2html(md, basepath):
|
||||
html = ''
|
||||
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
|
||||
# I personaly edited the file (markdown2.py:1743)
|
||||
html = '\n'.join(html)
|
||||
|
||||
html = html.replace(' ', ' espace;') # save where are the spaces
|
||||
|
||||
html = HTMLParser().unescape(html)
|
||||
|
||||
html = escape_amp(html)
|
||||
|
||||
# exception, again, because <pre> aren't supported by the phantoms
|
||||
html = html.replace(' espace;', '<i class="space">.</i>')
|
||||
html = replace_img_src_base64(html, basepath=os.path.dirname(
|
||||
md_view.file_name()))
|
||||
html = replace_img_src_base64(html, basepath=os.path.dirname(basepath))
|
||||
return html
|
||||
|
||||
def show_html(md_view, preview):
|
||||
global windows_phantom_set
|
||||
html = markdown2html(get_view_content(md_view), os.path.dirname(md_view.file_name()))
|
||||
|
||||
phantom_set = windows_phantom_set.setdefault(preview.window().id(),
|
||||
sublime.PhantomSet(preview,
|
||||
'markdown_live_preview'))
|
||||
sublime.PhantomSet(preview, 'markdown_live_preview'))
|
||||
phantom_set.update([sublime.Phantom(sublime.Region(0), html, sublime.LAYOUT_BLOCK,
|
||||
lambda href: sublime.run_command('open_url',
|
||||
{'url': href}))])
|
||||
lambda href: sublime.run_command('open_url', {'url': href}))])
|
||||
|
||||
# lambda href: sublime.run_command('open_url', {'url': href})
|
||||
# get the "ratio" of the markdown view's position.
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
Fast:
|
||||
☐ sync scroll @needsUpdate(because of images)
|
||||
☐ cache image in object when used, so that it's faster @needsTest
|
||||
|
||||
Medium:
|
||||
☐ auto refresh preview if loading images
|
||||
☐ use alt attribute for 404 error
|
||||
☐ fix custom css @bug
|
||||
|
||||
Long:
|
||||
☐ support hanchor (TOC) @big
|
||||
☐ support anchor (TOC) @big
|
||||
|
||||
Unknown:
|
||||
☐ check how many times is the show_html function called
|
||||
|
||||
|
||||
___________________
|
||||
Archive:
|
||||
✔ fix custom css @bug @done Sun 22 Jan 2017 at 18:40 @project(Medium)
|
||||
✘ check how many times is the show_html function called @cancelled Sun 22 Jan 2017 at 18:40 @project(Unknown)
|
||||
✔ sync scroll @needsUpdate(because of images) @done Sun 22 Jan 2017 at 18:39 @project(Fast)
|
||||
✔ fix #4 @high @done Mon 09 Jan 2017 at 18:42 @project(Long)
|
||||
✔ use MarkdownLivePreview syntax, so we can use syntax's settings @done Mon 09 Jan 2017 at 18:41 @project(Medium)
|
||||
✔ add clear cache command @done Mon 09 Jan 2017 at 18:41 @project(Fast)
|
||||
|
||||
30
default.css
30
default.css
@ -1,19 +1,21 @@
|
||||
html {
|
||||
--light-bg: color(var(--background) blend(#999 85%));
|
||||
--very-light-bg: color(var(--background) blend(#999 92%));
|
||||
}
|
||||
|
||||
body {
|
||||
padding:10px;
|
||||
padding-top: 0px;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
background-color: var(--background);
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
font-style: italic;
|
||||
display: block;
|
||||
margin-left: 30px;
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
code {
|
||||
@ -22,28 +24,36 @@ code {
|
||||
background-color: var(--light-bg);
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
line-height: 1.7;
|
||||
background-color: var(--light-bg);
|
||||
padding-left: 10px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
pre code {
|
||||
padding-left: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
pre code .space {
|
||||
color: var(--light-bg);
|
||||
}
|
||||
pre.table {
|
||||
background-color: var(--backgroud);
|
||||
}
|
||||
pre.table code {
|
||||
background-color: var(--backgroud);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0 .29412em;
|
||||
border-radius: .2rem;
|
||||
background-color: #f5f5f5;
|
||||
color: #555;
|
||||
box-shadow: 0 0.1rem 0 #b0b0b0;
|
||||
word-break: break-word;
|
||||
padding: 0 5px;
|
||||
background-color: var(--very-light-bg);
|
||||
font-family: "Roboto Mono","Courier New",Courier,monospace;
|
||||
}
|
||||
|
||||
7
dependencies.json
Normal file
7
dependencies.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"*": {
|
||||
"*": [
|
||||
"bs4"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -7,14 +7,15 @@ import os.path
|
||||
class MLPDevListener(sublime_plugin.EventListener):
|
||||
|
||||
def on_post_save(self, view):
|
||||
return
|
||||
# return
|
||||
if not (os.path.dirname(__file__) in view.file_name() and
|
||||
view.file_name().endswith('.py')):
|
||||
return
|
||||
sublime.run_command('reload_plugin', {
|
||||
'main': os.path.join(sublime.packages_path(),
|
||||
'MarkdownLivePreview', 'md_in_popup.py'),
|
||||
'main': os.path.join(sublime.packages_path(), 'MarkdownLivePreview',
|
||||
'MarkdownLivePreview.py'),
|
||||
'scripts': ['image_manager', 'functions', 'MLPApi',
|
||||
'setting_names'],
|
||||
'folders': ['lib'],
|
||||
'quiet': True
|
||||
})
|
||||
|
||||
@ -59,7 +59,26 @@ As told in the introduction, MarkdownLivePreview is very easy to use:
|
||||
!!! tip
|
||||
[Markdown Extended][] is supported too!
|
||||
|
||||
That's it.
|
||||
That's it. That's all you need to do to preview your markdown!
|
||||
|
||||
### Custom CSS
|
||||
|
||||
If you want to, you can add custom `CSS` to the MarkdownLivePreview's default stylesheet.
|
||||
|
||||
Just search for `MarkdownLivePreview: Edit Custom CSS File` in the command palette
|
||||
(<kbd>ctrl+shift+p</kbd>). It will open a file in which you can add some CSS that will be *added* to
|
||||
the normal CSS.
|
||||
|
||||
!!! bug
|
||||
Comments in the CSS is interpreted weirdly by Sublime Text's phantoms. After a few tests, I
|
||||
think that everything that is bellow a comment is ignored.
|
||||
|
||||
If you want to be sure that your CSS works, don't put any comments in it
|
||||
|
||||
#### Share your tweaks!
|
||||
|
||||
If you think that other users would enjoy your added CSS, then raise an issue, or PR the
|
||||
[GitHub repo][] to share your tweaks!
|
||||
|
||||
### Clearing the cache
|
||||
|
||||
@ -115,7 +134,7 @@ Here's what I'd recommend (and use):
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
!!! tip
|
||||
On Windows at least, you can press <kbd>alt</kbd> to focus (so show) the menu, even if they're
|
||||
originally hidden
|
||||
|
||||
@ -130,3 +149,4 @@ frameborder="0" scrolling="0" width="160px" height="30px"></iframe>!
|
||||
[pck-con]: https://packagecontrol.io
|
||||
[install-pck-con]: https://packagecontrol.io/installation
|
||||
[tweet]: https://twitter.com/_math2001
|
||||
[GitHub repo]: https://github.com/math2001/MarkdownLivePreview/issues
|
||||
|
||||
18
functions.py
18
functions.py
@ -4,6 +4,7 @@ import os.path
|
||||
import sublime
|
||||
import re
|
||||
from .image_manager import ImageManager
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
def plugin_loaded():
|
||||
global error404, loading
|
||||
@ -89,14 +90,9 @@ def get_settings():
|
||||
def pre_with_br(html):
|
||||
"""Because the phantoms of sublime text does not support <pre> blocks
|
||||
this function replaces every \n with a <br> in a <pre>"""
|
||||
|
||||
while True:
|
||||
obj = re.search(r'<pre>(.*?)</pre>', html, re.DOTALL)
|
||||
if not obj:
|
||||
break
|
||||
html = list(html)
|
||||
html[obj.start(0):obj.end(0)] = '<pre >' + ''.join(html[obj.start(1):obj.end(1)]) \
|
||||
.replace('\n', '<br>') \
|
||||
.replace(' ', ' ') + '</pre>'
|
||||
html = ''.join(html)
|
||||
return html
|
||||
soup = BeautifulSoup(html)
|
||||
for pre in soup.find_all('pre'):
|
||||
code = pre.find('code')
|
||||
code.replaceWith(BeautifulSoup(''.join(str(node) for node in pre.contents) \
|
||||
.replace('\n', '<br/>').replace(' ', '<i class="space">.</i>'), 'html.parser'))
|
||||
return str(soup).replace('<br/>', '<br />')
|
||||
|
||||
46
lib/pre_tables.py
Normal file
46
lib/pre_tables.py
Normal file
@ -0,0 +1,46 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'pre_tables' transform *html* tables into markdown tables, and put them in some <pre><code> tags
|
||||
"""
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
def python_table(s_table):
|
||||
"""Transform BeautifulSoup table into list of list"""
|
||||
rows = []
|
||||
for row in s_table.find_all('tr'):
|
||||
# rows.append(list(map( lambda td: td.text, row.find_all(['th', 'td']) )))
|
||||
rows.append(row.find_all(['th', 'td']))
|
||||
return rows
|
||||
|
||||
def pre_table(s_table):
|
||||
rows = python_table(s_table)
|
||||
cols_width = [len(cell) for cell in rows[0]]
|
||||
for j, row in enumerate(rows):
|
||||
for i, cell in enumerate(row):
|
||||
if cols_width[i] < len(cell.text):
|
||||
cols_width[i] = len(cell.text)
|
||||
text = '<pre class="table"><code>'
|
||||
for i, row in enumerate(rows):
|
||||
if i == 1:
|
||||
for j, cell in enumerate(row):
|
||||
text += '|' + '-' * (cols_width[j] + 2)
|
||||
text += '|\n'
|
||||
|
||||
for j, cell in enumerate(row):
|
||||
text += '| ' + ''.join(str(node) for node in cell.contents) \
|
||||
+ ' ' * (cols_width[j] - len(cell.text) + 1)
|
||||
text += '|\n'
|
||||
text += '</pre></code>'
|
||||
return text
|
||||
|
||||
def pre_tables(html):
|
||||
soup = BeautifulSoup(html, 'html.parser')
|
||||
for table in soup.find_all('table'):
|
||||
table.replace_with(BeautifulSoup(pre_table(table), 'html.parser'))
|
||||
return str(soup)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# CSW: ignore
|
||||
print(pre_tables(html))
|
||||
30
sample.md
30
sample.md
@ -4,8 +4,36 @@ Some `inline code` with *italic* and **bold** text.
|
||||
|
||||
```python
|
||||
import this
|
||||
if you('are', 'curious'):
|
||||
if you is moods.curious:
|
||||
print('then do it!')
|
||||
```
|
||||
|
||||
|
||||
<kbd>ctrl+\`</kbd> or *View → Show Console* and paste `import this`!
|
||||
|
||||
> Perfect programmers do NOT need comments.
|
||||
|
||||
- to be efficient
|
||||
- you need
|
||||
- todos
|
||||
|
||||
| ID | Name |
|
||||
|-----------|-------|
|
||||
| 56 | Matt |
|
||||
| 42 | Colin |
|
||||
| 23 | Lisa |
|
||||
| 45 | John |
|
||||
| `<table>` | `><` |
|
||||
|
||||
[Sublime Text Logo](https://upload.wikimedia.org/wikipedia/en/4/4c/Sublime_Text_Logo.png)
|
||||
|
||||
|
||||
|
||||
Some plugin I just *need*:
|
||||
|
||||
- [PackageResourceReviewer](https://packagecontrol.io/packages/PackageResourceViewer)
|
||||
- [Boxy Theme](https://packagecontrol.io/packages/Boxy%20Theme)
|
||||
- [Markdown Preview](https://packagecontrol.io/packages/Markdown%20Preview)
|
||||
- [FileManager](https://packagecontrol.io/packages/FileManager)
|
||||
- [PlainTasks](https://packagecontrol.io/packages/PlainTasks)
|
||||
- [JSONComma](https://packagecontrol.io/packages/JSONComma)
|
||||
|
||||
Reference in New Issue
Block a user