added prefix option

This commit is contained in:
2023-10-20 14:55:31 +08:00
parent 40bd2111bf
commit ef8da4e6cc
5 changed files with 26 additions and 14 deletions

View File

@@ -32,7 +32,7 @@ dependencies = [
]
[tool.setuptools.package-data]
md2html = ['static/*.html', 'static/*.css', 'static/*.js']
md2html = ['static/*']
[project.urls]
"Homepage" = "https://github.com/woggioni/md2html"

View File

@@ -1,20 +1,25 @@
import sys
from os.path import dirname, join, relpath
from time import time
from typing import Optional
from typing import Optional, TYPE_CHECKING
import markdown
if TYPE_CHECKING:
from _typeshed import StrOrBytesPath
STATIC_RESOURCES: set[str] = {
'/github-markdown.css',
'/custom.css',
'/hot-reload.js',
'/pygment.css',
'/markdown.svg'
}
STATIC_CACHE: dict[str, tuple[str, float]] = {}
MARDOWN_EXTENSIONS = ['extra', 'smarty', 'tables', 'codehilite']
def load_from_cache(path) -> tuple[str, float]:
global STATIC_CACHE
if path not in STATIC_CACHE:
@@ -24,7 +29,8 @@ def load_from_cache(path) -> tuple[str, float]:
def compile_html(url_path,
mdfile=None,
mdfile: 'StrOrBytesPath',
prefix: Optional['StrOrBytesPath'] = None,
extensions: Optional[list[str]] = None,
raw: bool = False) -> str:
with mdfile and open(mdfile, 'r') or sys.stdin as instream:
@@ -33,9 +39,9 @@ def compile_html(url_path,
doc = html
else:
parent = dirname(url_path)
prefix = relpath('/', start=parent)
prefix = prefix or relpath('/', start=parent)
script = f'<script src="{prefix}/hot-reload.js", type="text/javascript" defer="true"></script>'
css = ''
css = f'<link rel="icon" type="image/x-icon" href="{prefix}/markdown.svg">'
for css_file in ('github-markdown.css', 'pygment.css', 'custom.css'):
css += f' <link rel="stylesheet" href="{prefix}/{css_file}">'
doc = load_from_cache('/template.html')[0].format(content=html, script=script, css=css)

View File

@@ -1,6 +1,6 @@
import logging
from os import getcwd, listdir
from os.path import exists, splitext, isfile, join, relpath, isdir, basename, getmtime, dirname
from os.path import exists, splitext, isfile, join, relpath, isdir, basename, getmtime, dirname, normpath
from mimetypes import init as mimeinit, guess_type
import hashlib
from .md2html import compile_html, load_from_cache, STATIC_RESOURCES, MARDOWN_EXTENSIONS
@@ -33,17 +33,20 @@ def is_dotfile(filepath):
class Server:
def __init__(self, root_dir: 'StrOrBytesPath' = getcwd()):
def __init__(self, root_dir: 'StrOrBytesPath' = getcwd(), prefix: Optional['StrOrBytesPath'] = None):
self.root_dir = root_dir
self.cache = dict['StrOrBytesPath', tuple[str, float]]()
self.file_watcher = FileWatcher(cwd)
self.logger = logging.getLogger(Server.__name__)
self.prefix = prefix and normpath(f'{prefix.decode()}')
def handle_request(self, method: str, url_path: str, etag: Optional[str], query_string: Optional[str], start_response):
if method != 'GET':
start_response('405', [])
return []
path: 'StrOrBytesPath' = join(self.root_dir, relpath(url_path, '/'))
relative_path = relpath(url_path, start=self.prefix or '/')
url_path: 'StrOrBytesPath' = normpath(join('/', relative_path))
path: 'StrOrBytesPath' = join(self.root_dir, relative_path)
if url_path in STATIC_RESOURCES:
content, mtime = load_from_cache(url_path)
content = content.encode()
@@ -186,14 +189,15 @@ class Server:
etag = Server.parse_etag(etag_header)
return etag, digest
@staticmethod
def render_markdown(url_path: 'StrOrBytesPath',
def render_markdown(self,
url_path: 'StrOrBytesPath',
path: str,
raw: bool,
digest: str,
start_response) -> list[bytes]:
body = compile_html(url_path,
path,
self.prefix,
MARDOWN_EXTENSIONS,
raw=raw).encode()
start_response('200 OK', [('Content-Type', 'text/html; charset=UTF-8'),
@@ -214,10 +218,11 @@ class Server:
start_response('404 NOT_FOUND', [])
return []
@staticmethod
def directory_listing(path_info, path) -> str:
def directory_listing(self, path_info, path) -> str:
icon_path = join(self.prefix or '', 'markdown.svg')
title = "Directory listing for %s" % path_info
result = "<!DOCTYPE html><html><head>"
result += f'<link rel="icon" type="image/x-icon" href="{icon_path}">'
result += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"
result += "<title>" + title + "</title></head>"
result += "<body><h1>" + title + "</h1><hr>"

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><rect fill="#fff" height="512" rx="15%" width="512"/><path d="m410 366h-308c-14 0-26-12-26-26v-170c0-14 12-26 26-26h307c14 0 26 12 26 26v170c0 14-11 26-25 26zm-308-204c-4 0-9 4-9 9v170c0 5 4 9 9 9h307c5 0 9-4 9-9v-171c0-5-4-9-9-9h-307zm26 153v-119h34l34 43 34-43h35v118h-34v-68l-34 43-34-43v68zm216 0-52-57h34v-61h34v60h34z"/></svg>

After

Width:  |  Height:  |  Size: 394 B

View File

@@ -1,6 +1,6 @@
import logging
from .server import Server
from uwsgi import log
from uwsgi import log, opt
class UwsgiHandler(logging.Handler):
def emit(self, record: logging.LogRecord) -> None:
@@ -13,7 +13,7 @@ logging.basicConfig(
handlers=[UwsgiHandler()]
)
server = Server()
server = Server(prefix=opt.get('prefix', None))
def application(env, start_response):
return server.handle_request(