Compare commits

...

49 Commits

Author SHA1 Message Date
f4e6cd4ab0 Update README.md 2025-05-06 06:51:29 +00:00
c90d3071ea Update README.md 2025-05-06 06:51:06 +00:00
9de735aace Update package 2025-04-25 10:05:20 +02:00
786a72126c fix attribute error 2025-04-25 10:05:17 +02:00
70022a9b6c Update package 2025-04-25 10:03:02 +02:00
1f7b68e432 potential fix for same window preview 2025-04-25 10:02:58 +02:00
507a7e5d92 Update package 2025-04-25 10:00:08 +02:00
cc5d737c16 add logging for debugging 2025-04-25 10:00:03 +02:00
a7116d7206 Update package 2025-04-25 09:55:16 +02:00
4563a0f653 potentially fixes view in same window 2025-04-25 09:55:12 +02:00
e7a15ea070 Update package 2025-04-25 09:51:21 +02:00
34f8b3d733 open view in current window not in new one 2025-04-25 09:51:10 +02:00
e6a880d2a4 Merge branch 'master' of git.0x42.cloud:christian.morpurgo/MarkdownLivePreview 2025-04-24 20:33:02 +02:00
9cb5e2087f Update package 2025-04-24 20:32:52 +02:00
20dc7da4e8 Update package 2025-04-24 20:32:22 +02:00
0413ecca4b fix resourcxe path if repository name is different 2025-04-24 20:32:19 +02:00
37660abe64 Update repository.json 2025-04-24 18:29:07 +00:00
c2093e19aa Update package 2025-04-24 20:25:57 +02:00
b9ee2819e3 adjust scxale added more tags 2025-04-24 20:25:49 +02:00
99a4f21be3 Update package 2025-04-24 20:20:12 +02:00
edb424de99 font scale fix 2025-04-24 20:20:08 +02:00
d89e34f3e2 Update package 2025-04-24 20:18:52 +02:00
ecfd19dd85 potential fix for font scaling 2025-04-24 20:18:48 +02:00
69c722a933 Update package 2025-04-24 20:14:13 +02:00
7c37a9e413 potential fix for fontscaling 2025-04-24 20:14:10 +02:00
89d712fcce Update package 2025-04-24 20:11:22 +02:00
9f243f09c9 fix 2025-04-24 20:11:19 +02:00
ce768dce10 Update package 2025-04-24 20:09:01 +02:00
731f2def96 loggin 2025-04-24 20:08:56 +02:00
b3ffe8bf55 Update package 2025-04-24 20:05:55 +02:00
8576d4a631 Update package 2025-04-24 20:02:45 +02:00
49329d1f64 potential fix for font_scale 2025-04-24 20:02:39 +02:00
21b67f5b86 Update package 2025-04-24 20:00:49 +02:00
837979232e fix because we are using python 3.3 sic 2025-04-24 20:00:38 +02:00
547225ac4d Update package 2025-04-24 19:59:00 +02:00
e05516ab22 log font_scale 2025-04-24 19:58:47 +02:00
bbb90a8a97 Update package 2025-04-24 19:55:01 +02:00
598e22002b potential fix for font scale not working 2025-04-24 19:54:50 +02:00
e81b359294 Update package 2025-04-24 19:48:09 +02:00
8709e88fbd Update package 2025-04-24 19:46:51 +02:00
b94ad5856d fix import 2025-04-24 19:46:39 +02:00
3004ab4b41 Update package 2025-04-24 19:43:26 +02:00
14f6474cd5 fixing import error 2025-04-24 19:43:14 +02:00
d0323405c0 Update package 2025-04-24 19:40:38 +02:00
661f5b8911 fix impoert for soupsieve 2025-04-24 19:40:29 +02:00
3947b4cc4d Update package 2025-04-24 19:36:33 +02:00
2b35cf5000 add test_import to be ignored on export 2025-04-24 19:36:25 +02:00
72c684e89c Update package 2025-04-24 19:32:11 +02:00
ae1ea101d2 update package 2025-04-24 19:32:01 +02:00
9 changed files with 265 additions and 32 deletions

2
.gitattributes vendored
View File

@ -1,3 +1,5 @@
docs/ export-ignore docs/ export-ignore
resources/ resources/
!resources/*.base64 !resources/*.base64
test_imports.py export-ignore
MarkdownLivePreview.sublime-package export-ignore

View File

@ -51,7 +51,7 @@ def plugin_loaded():
resources["stylesheet"] = get_resource("stylesheet.css") resources["stylesheet"] = get_resource("stylesheet.css")
# FIXME: how could we make this setting update without restarting sublime text # FIXME: how could we make this setting update without restarting sublime text
# and not loading it every update as well # and not loading it every update as well
DELAY = get_settings().get(SETTING_DELAY_BETWEEN_UPDATES) DELAY = get_settings().get(SETTING_DELAY_BETWEEN_UPDATES, 100) # Provide default
class MdlpInsertCommand(sublime_plugin.TextCommand): class MdlpInsertCommand(sublime_plugin.TextCommand):
@ -62,6 +62,7 @@ class MdlpInsertCommand(sublime_plugin.TextCommand):
class OpenMarkdownPreviewCommand(sublime_plugin.TextCommand): class OpenMarkdownPreviewCommand(sublime_plugin.TextCommand):
def run(self, edit): def run(self, edit):
print("--- MarkdownLivePreview: OpenMarkdownPreviewCommand running ---")
""" If the file is saved exists on disk, we close it, and reopen it in a new """ If the file is saved exists on disk, we close it, and reopen it in a new
window. Otherwise, we copy the content, erase it all (to close the file without window. Otherwise, we copy the content, erase it all (to close the file without
a dialog) and re-insert it into a new view into a new window """ a dialog) and re-insert it into a new view into a new window """
@ -69,22 +70,30 @@ class OpenMarkdownPreviewCommand(sublime_plugin.TextCommand):
original_view = self.view original_view = self.view
original_window_id = original_view.window().id() original_window_id = original_view.window().id()
file_name = original_view.file_name() file_name = original_view.file_name()
print("--- MarkdownLivePreview: Original view ID: {}, File: {}, Window ID: {} ---".format(original_view.id(), file_name, original_window_id))
syntax_file = original_view.settings().get("syntax") syntax_file = original_view.settings().get("syntax")
if file_name: # don't close the original view; keep it in your main window:
original_view.close() # if file_name:
else: # original_view.close()
# the file isn't saved, we need to restore the content manually # else:
# # the file isn't saved, we need to restore the content manually
# total_region = sublime.Region(0, original_view.size())
# content = original_view.substr(total_region)
# original_view.erase(edit, total_region)
# original_view.close()
# # FIXME: save the document to a temporary file, so that if we crash,
# # the user doesn't lose what he wrote
if not file_name:
# If the file isn't saved, we still need the content for the new view
total_region = sublime.Region(0, original_view.size()) total_region = sublime.Region(0, original_view.size())
content = original_view.substr(total_region) content = original_view.substr(total_region)
original_view.erase(edit, total_region) print("--- MarkdownLivePreview: Unsaved file, content length: {} ---".format(len(content)))
original_view.close()
# FIXME: save the document to a temporary file, so that if we crash,
# the user doesn't lose what he wrote
sublime.run_command("new_window") # instead of making a new window, grab your existing one:
preview_window = sublime.active_window() preview_window = original_view.window()
print("--- MarkdownLivePreview: Using existing window ID: {} ---".format(preview_window.id()))
preview_window.run_command( preview_window.run_command(
"set_layout", "set_layout",
@ -100,20 +109,44 @@ class OpenMarkdownPreviewCommand(sublime_plugin.TextCommand):
preview_view.set_scratch(True) preview_view.set_scratch(True)
preview_view.settings().set(PREVIEW_VIEW_INFOS, {}) preview_view.settings().set(PREVIEW_VIEW_INFOS, {})
preview_view.set_name("Preview") preview_view.set_name("Preview")
print("--- MarkdownLivePreview: Created preview_view ID: {} ---".format(preview_view.id()))
# FIXME: hide number lines on preview # FIXME: hide number lines on preview
preview_window.focus_group(0) preview_window.focus_group(0)
if file_name: if file_name:
markdown_view = preview_window.open_file(file_name) markdown_view = preview_window.open_file(file_name)
print("--- MarkdownLivePreview: Opened markdown_view ID: {} for file: {} ---".format(markdown_view.id(), file_name))
else: else:
markdown_view = preview_window.new_file() markdown_view = preview_window.new_file()
markdown_view.run_command("mdlp_insert", {"point": 0, "string": content}) markdown_view.run_command("mdlp_insert", {"point": 0, "string": content})
markdown_view.set_scratch(True) markdown_view.set_scratch(True)
print("--- MarkdownLivePreview: Created new markdown_view ID: {} for unsaved content ---".format(markdown_view.id()))
markdown_view.set_syntax_file(syntax_file) markdown_view.set_syntax_file(syntax_file)
markdown_view.settings().set( markdown_view.settings().set(
MARKDOWN_VIEW_INFOS, {"original_window_id": original_window_id,}, MARKDOWN_VIEW_INFOS, {"original_window_id": original_window_id, "preview_view_id": preview_view.id(),},
) )
infos_to_log = markdown_view.settings().get(MARKDOWN_VIEW_INFOS)
print("--- MarkdownLivePreview: Stored infos on markdown_view {}: {} ---".format(markdown_view.id(), infos_to_log))
# Manually trigger the initial setup and render via the listener
# Use set_timeout_async to run it after the command finishes
print("--- MarkdownLivePreview: Scheduling setup_and_update_preview for md_view: {}, pv_view: {} ---".format(markdown_view.id(), preview_view.id()))
sublime.set_timeout_async(lambda: self.trigger_listener_setup(markdown_view.id(), preview_view.id()), 0)
# Helper method to find and call the listener instance method
# This is needed because the listener isn't easily accessible directly from the command instance
def trigger_listener_setup(self, md_view_id, pv_view_id):
print("--- MarkdownLivePreview: trigger_listener_setup running for md_view: {}, pv_view: {} ---".format(md_view_id, pv_view_id))
# Access the listener instance directly via its class variable
listener_instance = MarkdownLivePreviewListener.instance
if listener_instance:
print("--- MarkdownLivePreview: Found listener instance via class variable, calling setup_and_update_preview ---")
listener_instance.setup_and_update_preview(md_view_id, pv_view_id)
else:
# This should ideally not happen if the listener loaded correctly before the command ran
print("--- MarkdownLivePreview: ERROR: MarkdownLivePreviewListener.instance is None! Cannot trigger setup. ---")
def is_enabled(self): def is_enabled(self):
# FIXME: is this the best way there is to check if the current syntax is markdown? # FIXME: is this the best way there is to check if the current syntax is markdown?
@ -124,6 +157,7 @@ class OpenMarkdownPreviewCommand(sublime_plugin.TextCommand):
class MarkdownLivePreviewListener(sublime_plugin.EventListener): class MarkdownLivePreviewListener(sublime_plugin.EventListener):
instance = None # Class variable to hold the single instance
phantom_sets = { phantom_sets = {
# markdown_view.id(): phantom set # markdown_view.id(): phantom set
@ -133,6 +167,11 @@ class MarkdownLivePreviewListener(sublime_plugin.EventListener):
# then, we update only if now() - last_update > DELAY # then, we update only if now() - last_update > DELAY
last_update = 0 last_update = 0
def __init__(self):
super().__init__() # Good practice to call super
MarkdownLivePreviewListener.instance = self
print("--- MarkdownLivePreview: Listener instance created and registered. ---")
# FIXME: maybe we shouldn't restore the file in the original window... # FIXME: maybe we shouldn't restore the file in the original window...
def on_pre_close(self, markdown_view): def on_pre_close(self, markdown_view):
@ -155,11 +194,24 @@ class MarkdownLivePreviewListener(sublime_plugin.EventListener):
def on_load_async(self, markdown_view): def on_load_async(self, markdown_view):
infos = markdown_view.settings().get(MARKDOWN_VIEW_INFOS) infos = markdown_view.settings().get(MARKDOWN_VIEW_INFOS)
if not infos: if not infos:
# print("--- MarkdownLivePreview: on_load_async ignored for view {} - no infos ---".format(markdown_view.id())) # Optional: very verbose
return return
preview_view = markdown_view.window().active_view_in_group(1) print("--- MarkdownLivePreview: on_load_async triggered for markdown_view {} ---".format(markdown_view.id()))
preview_view_id = infos.get("preview_view_id")
if not preview_view_id:
print("--- MarkdownLivePreview: ERROR in on_load_async: No preview_view_id found in infos: {} ---".format(infos))
return # Should not happen if setup was correct
self.phantom_sets[markdown_view.id()] = sublime.PhantomSet(preview_view) preview_view = sublime.View(preview_view_id)
if not preview_view.is_valid():
print("--- MarkdownLivePreview: ERROR in on_load_async: Preview view {} is no longer valid ---".format(preview_view_id))
return # Preview view was closed before loading finished
print("--- MarkdownLivePreview: on_load_async found valid preview_view {} ---".format(preview_view.id()))
# PhantomSet creation is now handled by setup_and_update_preview triggered from the command
# self.phantom_sets[markdown_view.id()] = sublime.PhantomSet(preview_view)
# print("--- MarkdownLivePreview: PhantomSet created in on_load_async for preview_view {} ---".format(preview_view.id())) # Keep log commented
self._update_preview(markdown_view) self._update_preview(markdown_view)
def on_close(self, markdown_view): def on_close(self, markdown_view):
@ -169,13 +221,11 @@ class MarkdownLivePreviewListener(sublime_plugin.EventListener):
if not infos: if not infos:
return return
assert ( if markdown_view.id() in self.phantom_sets:
markdown_view.id() == self.markdown_view.id()
), "pre_close view.id() != close view.id()"
del self.phantom_sets[markdown_view.id()] del self.phantom_sets[markdown_view.id()]
self.preview_window.run_command("close_window") # don't close the entire window—just let the user close the preview tab:
# self.preview_window.run_command("close_window")
# find the window with the right id # find the window with the right id
original_window = next( original_window = next(
@ -206,14 +256,17 @@ class MarkdownLivePreviewListener(sublime_plugin.EventListener):
# @min_time_between_call(.5) # @min_time_between_call(.5)
def on_modified_async(self, markdown_view): def on_modified_async(self, markdown_view):
# print("--- MarkdownLivePreview: on_modified_async triggered for view {} ---".format(markdown_view.id())) # Optional: very verbose
infos = markdown_view.settings().get(MARKDOWN_VIEW_INFOS) infos = markdown_view.settings().get(MARKDOWN_VIEW_INFOS)
if not infos: if not infos:
return return
print("--- MarkdownLivePreview: Scheduling update for markdown_view {} ---".format(markdown_view.id()))
# we schedule an update, which won't run if an # we schedule an update, which won't run if an
sublime.set_timeout(partial(self._update_preview, markdown_view), DELAY) sublime.set_timeout(partial(self._update_preview, markdown_view), DELAY)
def _update_preview(self, markdown_view): def _update_preview(self, markdown_view):
print("--- MarkdownLivePreview: _update_preview called for markdown_view {} ---".format(markdown_view.id()))
# if the buffer id is 0, that means that the markdown_view has been closed # 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 # 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 # are loaded from the internet (ie. it could finish loading *after* the user
@ -222,25 +275,53 @@ class MarkdownLivePreviewListener(sublime_plugin.EventListener):
settings = get_settings() settings = get_settings()
delay = settings.get(SETTING_DELAY_BETWEEN_UPDATES, 100) # Provide default delay = settings.get(SETTING_DELAY_BETWEEN_UPDATES, 100) # Provide default
font_scale = settings.get(SETTING_FONT_SCALE, 1.0) # Provide default font_scale = settings.get(SETTING_FONT_SCALE, 1.0) # Provide default
print("--- MarkdownLivePreview: Using font_scale: {} ---".format(font_scale))
if time.time() - self.last_update < delay / 1000: if time.time() - self.last_update < delay / 1000:
print("--- MarkdownLivePreview: Update skipped for view {} due to time delay ---".format(markdown_view.id()))
return return
if markdown_view.buffer_id() == 0: if markdown_view.buffer_id() == 0:
print("--- MarkdownLivePreview: Update skipped for view {}: buffer_id is 0 (view closed) ---".format(markdown_view.id()))
return return
# Check if the phantom set still exists for this view ID
if markdown_view.id() not in self.phantom_sets:
print("--- MarkdownLivePreview: Update skipped for view {}: No phantom set found ---".format(markdown_view.id()))
# View might have been closed between modification and update
return
print("--- MarkdownLivePreview: Update proceeding for view {} ---".format(markdown_view.id()))
self.last_update = time.time() self.last_update = time.time()
total_region = sublime.Region(0, markdown_view.size()) total_region = sublime.Region(0, markdown_view.size())
markdown = markdown_view.substr(total_region) markdown = markdown_view.substr(total_region)
print("--- MarkdownLivePreview: Read markdown content (length: {}) ---".format(len(markdown)))
preview_view = markdown_view.window().active_view_in_group(1) infos = markdown_view.settings().get(MARKDOWN_VIEW_INFOS)
if not infos:
print("--- MarkdownLivePreview: ERROR in _update_preview: No infos found for view {} ---".format(markdown_view.id()))
return # Should not happen
preview_view_id = infos.get("preview_view_id")
if not preview_view_id:
print("--- MarkdownLivePreview: ERROR in _update_preview: No preview_view_id found in infos: {} ---".format(infos))
return # Should not happen
preview_view = sublime.View(preview_view_id)
if not preview_view.is_valid():
print("--- MarkdownLivePreview: ERROR in _update_preview: Preview view {} is no longer valid ---".format(preview_view_id))
return # Preview view was closed
print("--- MarkdownLivePreview: Found valid preview_view {} for update ---".format(preview_view.id()))
# Get viewport_width, default to a large value if view isn't ready # Get viewport_width, default to a large value if view isn't ready
viewport_extent = preview_view.viewport_extent() viewport_extent = preview_view.viewport_extent()
viewport_width = viewport_extent[0] if viewport_extent else 1024 viewport_width = viewport_extent[0] if viewport_extent else 1024
print("--- MarkdownLivePreview: Viewport width: {} ---".format(viewport_width))
basepath = os.path.dirname(markdown_view.file_name()) if markdown_view.file_name() else '.' # Handle unsaved files basepath = os.path.dirname(markdown_view.file_name()) if markdown_view.file_name() else '.' # Handle unsaved files
print("--- MarkdownLivePreview: Calling markdown2html with basepath: {} ---".format(basepath))
html = markdown2html( html = markdown2html(
markdown, markdown,
basepath, basepath,
@ -250,6 +331,10 @@ class MarkdownLivePreviewListener(sublime_plugin.EventListener):
font_scale, font_scale,
) )
# Truncate HTML safely for logging
html_preview = html[:100].replace('\n', ' ') # Avoid breaking log lines
print("--- MarkdownLivePreview: Generated HTML (starts with): {}... ---".format(html_preview))
self.phantom_sets[markdown_view.id()].update( self.phantom_sets[markdown_view.id()].update(
[ [
sublime.Phantom( sublime.Phantom(
@ -260,6 +345,32 @@ class MarkdownLivePreviewListener(sublime_plugin.EventListener):
) )
] ]
) )
print("--- MarkdownLivePreview: Updated phantoms in preview_view {} ---".format(preview_view.id()))
def setup_and_update_preview(self, markdown_view_id, preview_view_id):
print("--- MarkdownLivePreview: setup_and_update_preview called for md_view: {}, pv_view: {} ---".format(markdown_view_id, preview_view_id))
markdown_view = sublime.View(markdown_view_id)
preview_view = sublime.View(preview_view_id)
if not markdown_view.is_valid():
print("--- MarkdownLivePreview: ERROR in setup_and_update: markdown_view {} is not valid ---".format(markdown_view_id))
return
if not preview_view.is_valid():
print("--- MarkdownLivePreview: ERROR in setup_and_update: preview_view {} is not valid ---".format(preview_view_id))
return
# Create PhantomSet if it doesn't exist (shouldn't at this point)
if markdown_view_id not in self.phantom_sets:
print("--- MarkdownLivePreview: Creating PhantomSet for preview_view {} in setup ---".format(preview_view.id()))
self.phantom_sets[markdown_view_id] = sublime.PhantomSet(preview_view)
else:
# This case might occur if the command is run multiple times rapidly? Ensure it's associated correctly.
print("--- MarkdownLivePreview: Warning: PhantomSet already existed for markdown_view {} in setup. Re-associating with preview_view {}. ---".format(markdown_view_id, preview_view.id()))
self.phantom_sets[markdown_view_id].view = preview_view # Ensure it points to the correct view
# Trigger the first update
print("--- MarkdownLivePreview: Triggering initial _update_preview from setup ---")
self._update_preview(markdown_view)
def get_settings(): def get_settings():
@ -267,11 +378,15 @@ def get_settings():
def get_resource(resource): def get_resource(resource):
path = "Packages/MarkdownLivePreview/resources/" + resource package_name = __package__ # Get the current package name dynamically
abs_path = os.path.join(sublime.packages_path(), "..", path) path = "Packages/{}/resources/{}".format(package_name, resource)
# Original logic: check absolute path first (useful for unpacked development)
# Adjusted abs_path to use dynamic package_name
abs_path = os.path.join(sublime.packages_path(), package_name, "resources", resource)
if os.path.isfile(abs_path): if os.path.isfile(abs_path):
with open(abs_path, "r") as fp: with open(abs_path, "r") as fp:
return fp.read() return fp.read()
# Fallback to sublime.load_resource (works for packed and unpacked)
return sublime.load_resource(path) return sublime.load_resource(path)

Binary file not shown.

View File

@ -1,5 +1,25 @@
# MarkdownLivePreview # MarkdownLivePreview
## Acknowledgments
This project is a fork of [MarkdownLivePreview](https://github.com/math2001/MarkdownLivePreview) by **math2001**. I'm grateful for the original implementation, which provided a solid foundation for live Markdown preview in Sublime Text.
Many thanks to math2001 for the original code—this fork wouldn't have been possible without their work.
## Changes contained in this Fork
In this fork ([christian.morpurgo/MarkdownLivePreview](https://git.0x42.cloud/christian.morpurgo/MarkdownLivePreview)), I've made the following enhancements:
- **Bundled `bs4` and `soupsieve`**
Repackaged both libraries as standalone modules by rewriting their imports, resolving errors when Sublime Text 4 attempted to install these old versions as external dependencies.
- **`font_scale` option**
Added a new `font_scale: number` setting to allow users to increase or decrease the preview text size directly from their Sublime Text settings.
- **In-window preview**
Changed the preview behavior so that starting a preview reuses the current window instead of opening a new one.
A simple plugin to preview your markdown as you type right in Sublime Text. A simple plugin to preview your markdown as you type right in Sublime Text.
No dependencies! No dependencies!
@ -31,7 +51,7 @@ could be working on, then there are a bunch of `FIXME`s all over this package.
Just pick one and fix it :-) Just pick one and fix it :-)
``` ```
$ git clone https://github.com/math2001/MarkdownLivePreview $ git clone https://git.0x42.cloud/christian.morpurgo/MarkdownLivePreview
$ cd MarkdownLivePreview $ cd MarkdownLivePreview
$ grep -R FIXME $ grep -R FIXME
``` ```

6
create_package.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
git archive --format=zip --prefix="" --output=MarkdownLivePreview.sublime-package master
git add MarkdownLivePreview.sublime-package
git commit -m "Update package"
git push origin master

View File

@ -9,8 +9,10 @@ import re
import sys import sys
import warnings import warnings
try: try:
from ..soupsieve import * # We are installed under the bs4 package
from soupsieve import *
except ImportError as e: except ImportError as e:
# We are installed standalone, or soupsieve is not installed.
soupsieve = None soupsieve = None
warnings.warn( warnings.warn(
'The soupsieve package is not installed. CSS selectors cannot be used.' 'The soupsieve package is not installed. CSS selectors cannot be used.'

View File

@ -12,6 +12,7 @@ import concurrent.futures
import urllib.request import urllib.request
import base64 import base64
from .lib.bs4 import BeautifulSoup as bs4 from .lib.bs4 import BeautifulSoup as bs4
from .lib.bs4.element import Comment
from functools import partial from functools import partial
@ -33,7 +34,7 @@ def markdown2html(markdown, basepath, re_render, resources, viewport_width, font
""" """
html = markdowner.convert(markdown) html = markdowner.convert(markdown)
soup = bs4.BeautifulSoup(html, "html.parser") soup = bs4(html, "html.parser")
for img_element in soup.find_all("img"): for img_element in soup.find_all("img"):
src = img_element["src"] src = img_element["src"]
@ -61,7 +62,7 @@ def markdown2html(markdown, basepath, re_render, resources, viewport_width, font
# remove comments, because they pollute the console with error messages # remove comments, because they pollute the console with error messages
for comment_element in soup.find_all( for comment_element in soup.find_all(
text=lambda text: isinstance(text, bs4.Comment) text=lambda text: isinstance(text, Comment)
): ):
comment_element.extract() comment_element.extract()
@ -79,14 +80,61 @@ def markdown2html(markdown, basepath, re_render, resources, viewport_width, font
.replace("\n", "<br />") .replace("\n", "<br />")
) )
code_element.replace_with(bs4.BeautifulSoup(fixed_pre, "html.parser")) code_element.replace_with(bs4(fixed_pre, "html.parser"))
# FIXME: highlight the code using Sublime's syntax # FIXME: highlight the code using Sublime's syntax
# Apply font scaling via inline styles
if font_scale != 1.0:
BASE_PX_SIZE = 15 # Base font size in pixels
TAG_MULTIPLIERS = {
'p': 1.0,
'li': 1.0,
'h1': 2.0,
'h2': 1.8,
'h3': 1.6,
'h4': 1.4,
'h5': 1.2,
'h6': 1.1,
'blockquote': 1.0,
'td': 1.0,
'th': 1.0,
'dt': 1.0,
'dd': 1.0,
'table': 1.0,
'tr': 1.0,
'ul': 1.0,
'ol': 1.0,
'code': 1.0,
'pre': 1.0,
'a': 1.0,
'strong': 1.0,
'em': 1.0,
's': 1.0,
'sup': 1.0,
'sub': 1.0,
'mark': 1.0,
'small': 1.0,
'big': 1.0,
'kbd': 1.0,
'samp': 1.0,
'var': 1.0,
'cite': 1.0,
'dfn': 1.0,
'abbr': 1.0,
'acronym': 1.0,
}
# Find all tags that we want to scale
for element in soup.find_all(list(TAG_MULTIPLIERS.keys())):
multiplier = TAG_MULTIPLIERS.get(element.name, 1.0)
target_size = round(BASE_PX_SIZE * multiplier * font_scale)
# Simple style setting (overwrites existing inline style if any)
# A more robust solution would parse and merge existing styles
element['style'] = "font-size: {}px;".format(target_size)
# FIXME: report that ST doesn't support <br/> but does work with <br />... WTF? # FIXME: report that ST doesn't support <br/> but does work with <br />... WTF?
# Add font scaling CSS rule stylesheet = resources["stylesheet"] # Use only the base stylesheet
font_scale_css = "body {{ font-size: {}em; }}\n".format(font_scale)
stylesheet = font_scale_css + resources["stylesheet"]
return "<style>\n{}\n</style>\n\n{}".format(stylesheet, soup).replace( return "<style>\n{}\n</style>\n\n{}".format(stylesheet, soup).replace(
"<br/>", "<br />" "<br/>", "<br />"

View File

@ -2,7 +2,7 @@
"schema_version": "3.0.0", "schema_version": "3.0.0",
"packages": [ "packages": [
{ {
"name": "MarkdownLivePreview", "name": "MarkdownLivePreview-FORK",
"description": "My enhanced live-preview fork of MarkdownLivePreview", "description": "My enhanced live-preview fork of MarkdownLivePreview",
"author": "Christian Morpurgo", "author": "Christian Morpurgo",
"homepage": "https://git.0x42.cloud/christian.morpurgo/MarkdownLivePreview", "homepage": "https://git.0x42.cloud/christian.morpurgo/MarkdownLivePreview",

40
test_imports.py Normal file
View File

@ -0,0 +1,40 @@
# test_imports.py
import sys
import os
# Optional: Explicitly add project root to path if needed,
# although running from the root often suffices.
# project_root = os.path.dirname(__file__)
# if project_root not in sys.path:
# sys.path.insert(0, project_root)
print("Attempting imports...")
try:
# Try importing the main entry point for bs4 from the lib structure
from lib.bs4 import BeautifulSoup
print("- Successfully imported BeautifulSoup from lib.bs4")
# Try creating a simple soup object (tests basic bs4 internal imports)
soup = BeautifulSoup("<a></a>", "html.parser")
print(f"- Created soup object: {soup.a}")
# Try importing the main entry point for soupsieve
from lib.soupsieve import compile as soupsieve_compile
print("- Successfully imported compile from lib.soupsieve")
# Try compiling a simple selector (tests basic soupsieve internal imports)
compiled = soupsieve_compile("a")
print(f"- Compiled selector: {compiled.pattern}")
# Try using the selector (tests soupsieve -> bs4 interaction)
match = compiled.select_one(soup)
print(f"- Selector match: {match}")
print("\nBasic import and usage tests passed!")
except ImportError as e:
print(f"\nImport Error: {e}")
print("Failed to import. Check paths and internal library structure.")
except Exception as e:
print(f"\nRuntime Error: {e}")
print("Imports might have worked, but usage failed.")