Viewing images works for local files

We have to make sure that everything is converted to base64 (and
replaced in the src attribute) because otherwise ST3 messes up the
height of the images
This commit is contained in:
Mathieu PATUREL
2019-11-14 17:28:02 +11:00
parent 5738f6b5ff
commit bae26fc452
6 changed files with 111 additions and 16 deletions

View File

@ -1,7 +1,10 @@
import os.path
import sublime
import sublime_plugin
from .lib.markdown2 import Markdown
from functools import partial
from .markdown2html import markdown2html
from .utils import *
def plugin_loaded():
@ -85,8 +88,6 @@ class OpenMarkdownPreviewCommand(sublime_plugin.TextCommand):
class MarkdownLivePreviewListener(sublime_plugin.EventListener):
markdowner = Markdown()
phantom_sets = {
# markdown_view.id(): phantom set
}
@ -161,17 +162,23 @@ class MarkdownLivePreviewListener(sublime_plugin.EventListener):
self._update_preview(markdown_view)
def _update_preview(self, markdown_view):
print('update markdown view', markdown_view.is_loading())
# if the buffer id is 0, that means that the markdown_view has been closed
# This check is needed since a this function is used as a callback for when images
# are loaded from the internet (ie. it could finish loading *after* the user
# closes the markdown_view)
if markdown_view.buffer_id() == 0:
return
total_region = sublime.Region(0, markdown_view.size())
markdown = markdown_view.substr(total_region)
html = self.markdowner.convert(markdown)
print(html)
# FIXME: replace images
basepath = os.path.dirname(markdown_view.file_name())
html = markdown2html(markdown, basepath, partial(self._update_preview,
markdown_view))
self.phantom_sets[markdown_view.id()].update([
sublime.Phantom(sublime.Region(0), html, sublime.LAYOUT_BLOCK,
lambda href: sublime.run_command('open_url', {'url': href}))
])

7
dependencies.json Normal file
View File

@ -0,0 +1,7 @@
{
"*": {
"*": [
"bs4"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

20
live-testing/test.md Normal file
View File

@ -0,0 +1,20 @@
# hello world
This is a *test*.
I'm not sure that it **actually** going to work, but it seems nicer than the [previous version][prev]
This is the first image from the local file system (absolute path, sorry):
![The sublime text logo!](file:///home/math2001/.config/sublime-text-3/Packages/MarkdownLivePreview2/live-testing/sublime_text.png)
This is the first image from the local file system, *relative* path!
![The sublime text logo!](sublime_text.png)
This is the first image from the internet!
![The sublime text logo!](https://www.sublimehq.com/images/sublime_text.png)
[prev]: https://github.com/math2001/MarkdownLivePreview/tree/d4c477749ce7e77b8e9fc85464a2488f003c45bc

69
markdown2html.py Normal file
View File

@ -0,0 +1,69 @@
import base64
import os.path
from functools import lru_cache
from .lib.markdown2 import Markdown
from bs4 import BeautifulSoup
__all__ = ('markdown2html', )
markdowner = Markdown()
# FIXME: put a nice picture please :^)
BASE64_LOADING_IMAGE = 'loading image!'
BASE64_404_IMAGE = '404 not found :-('
class LoadingError(Exception):
pass
def markdown2html(markdown, basepath, re_render):
""" converts the markdown to html, loads the images and puts in base64 for sublime
to understand them correctly. That means that we are responsible for loading the
images from the internet. Hence, we take in re_render, which is just a function we
call when an image has finished loading to retrigger a render (see #90)
"""
html = markdowner.convert(markdown)
soup = BeautifulSoup(html, "html.parser")
for img_element in soup.find_all('img'):
src = img_element['src']
# already in base64, or something of the like
# FIXME: what other types are possible? Are they handled by ST? If not, could we
# convert it into base64? is it worth the effort?
if src.startswith('data:image/'):
continue
if src.startswith('http://') or src.startswith('https://'):
path = src
elif src.startswith('file://'):
path = src[len('file://'):]
else:
# expanduser: ~ -> /home/math2001
# realpath: simplify that paths so that we don't have duplicated caches
path = os.path.realpath(os.path.expanduser(os.path.join(basepath, src)))
try:
base64 = get_base64_image(path)
except FileNotFoundError as e:
print("{!r} not found {!r}".format(path, e))
base64 = BASE64_404_IMAGE
except LoadingError:
# the image is loading
base64 = BASE64_LOADING_IMAGE
img_element['src'] = base64
# FIXME: how do tables look? should we use ascii tables?
return str(soup)
# FIXME: This is an in memory cache. 20 seems like a fair bit of images... Should it be
# bigger? Should the user be allowed to chose? There definitely should be a limit
# because we don't wanna use to much memory, we're a simple markdown preview plugin
@lru_cache(maxsize=20)
def get_base64_image(path):
if path.startswith('http://') or path.startswith('https://'):
return 'loading of the internet!'
with open(path, 'rb') as fp:
return 'data:image/png;base64,' + base64.b64encode(fp.read()).decode('utf-8')

View File

@ -1,8 +0,0 @@
# hello world
This is a *test*.
I'm not sure that it **actually** going to work, but it seems nicer than the [previous version][prev]
[prev]: https://github.com/math2001/MarkdownLivePreview/tree/d4c477749ce7e77b8e9fc85464a2488f003c45bc