markdown-up 2.1.4__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- markdown_up-2.2.0/PKG-INFO +150 -0
- markdown_up-2.2.0/README.md +125 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/setup.cfg +2 -2
- markdown_up-2.2.0/src/markdown_up/app.py +283 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/main.py +23 -17
- markdown_up-2.2.0/src/markdown_up/static/index.html +54 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/static/markdownUpIndex.bare +17 -19
- markdown_up-2.2.0/src/markdown_up.egg-info/PKG-INFO +150 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/requires.txt +1 -1
- markdown_up-2.1.4/PKG-INFO +0 -63
- markdown_up-2.1.4/README.md +0 -38
- markdown_up-2.1.4/src/markdown_up/app.py +0 -207
- markdown_up-2.1.4/src/markdown_up/static/index.html +0 -54
- markdown_up-2.1.4/src/markdown_up.egg-info/PKG-INFO +0 -63
- {markdown_up-2.1.4 → markdown_up-2.2.0}/LICENSE +0 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/pyproject.toml +0 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/__init__.py +0 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/__main__.py +0 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/static/__init__.py +0 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/SOURCES.txt +0 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/dependency_links.txt +0 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/entry_points.txt +0 -0
- {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: markdown-up
|
|
3
|
+
Version: 2.2.0
|
|
4
|
+
Summary: The MarkdownUp launcher
|
|
5
|
+
Home-page: https://github.com/craigahobbs/markdown-up-py
|
|
6
|
+
Author: Craig A. Hobbs
|
|
7
|
+
Author-email: craigahobbs@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: Markdown,viewer
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: chisel>=1.5.0
|
|
23
|
+
Requires-Dist: waitress>=3.0.0
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# markdown-up
|
|
27
|
+
|
|
28
|
+
[](https://pypi.org/project/markdown-up/)
|
|
29
|
+
[](https://pypi.org/project/markdown-up/)
|
|
30
|
+
[](https://github.com/craigahobbs/markdown-up-py/blob/main/LICENSE)
|
|
31
|
+
[](https://pypi.org/project/markdown-up/)
|
|
32
|
+
|
|
33
|
+
MarkdownUp is a Markdown viewer.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## Install MarkdownUp
|
|
37
|
+
|
|
38
|
+
Use Python's `pip` to install MarkdownUp as follows:
|
|
39
|
+
|
|
40
|
+
~~~
|
|
41
|
+
pip install markdown-up
|
|
42
|
+
~~~
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## View Markdown Files
|
|
46
|
+
|
|
47
|
+
To start MarkdownUp, open a terminal and run the `markdown-up` application:
|
|
48
|
+
|
|
49
|
+
~~~
|
|
50
|
+
markdown-up
|
|
51
|
+
~~~
|
|
52
|
+
|
|
53
|
+
The `markdown-up` application opens the web browser to the MarkdownUp file browser, which allows you
|
|
54
|
+
to view Markdown or HTML files and navigate directories. To view a file, click on its link.
|
|
55
|
+
|
|
56
|
+
You can view a specific file as follows:
|
|
57
|
+
|
|
58
|
+
~~~
|
|
59
|
+
markdown-up README.md
|
|
60
|
+
~~~
|
|
61
|
+
|
|
62
|
+
**Note:** MarkdownUp runs entirely offline. It does not use an external service to render Markdown
|
|
63
|
+
files.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Running MarkdownUp
|
|
67
|
+
|
|
68
|
+
When you run the `markdown-up` application, in addition to opening the web browser, it starts a
|
|
69
|
+
[chisel](https://pypi.org/project/chisel/)
|
|
70
|
+
backend API application using
|
|
71
|
+
[waitress](https://pypi.org/project/waitress/).
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### Automatically Creates HTML for Markdown Files
|
|
75
|
+
|
|
76
|
+
When you run MarkdownUp and click on a Markdown file link, the link navigates to an HTML file that
|
|
77
|
+
renders the Markdown file. Every Markdown file hosted by MarkdownUp has a corresponding `.html` file
|
|
78
|
+
of the same name. For example, if you run Markdown up in a directory that has the following Markdown
|
|
79
|
+
files: "README.md" and "CHANGELOG.md". The MarkdownUp service automatically generates "README.html"
|
|
80
|
+
and "CHANGELOG.html" files.
|
|
81
|
+
|
|
82
|
+
The generated `.html` files are HTML stubs for the
|
|
83
|
+
[MarkdownUp Front-End Application](https://github.com/craigahobbs/markdown-up#readme).
|
|
84
|
+
All Markdown parsing and rendering are done on the client to minimize server costs.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
### Command-Line Arguments
|
|
88
|
+
|
|
89
|
+
The `markdown-up` application has the following command-line arguments:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
usage: markdown-up [-h] [-p N] [-t N] [-n] [-r] [-q] [path]
|
|
93
|
+
|
|
94
|
+
positional arguments:
|
|
95
|
+
path the file or directory to view (default is ".")
|
|
96
|
+
|
|
97
|
+
options:
|
|
98
|
+
-h, --help show this help message and exit
|
|
99
|
+
-p N the application port (default is 8080)
|
|
100
|
+
-t N the number of web server threads (default is 8)
|
|
101
|
+
-n don't open a web browser
|
|
102
|
+
-r release mode (cache statics, remove documentation and index)
|
|
103
|
+
-q don't display access logging
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
## MarkdownUp Applications
|
|
108
|
+
|
|
109
|
+
[MarkdownUp Applications](https://github.com/craigahobbs/markdown-up?tab=readme-ov-file#dynamic-markdown-applications)
|
|
110
|
+
are front-end applications that run within the
|
|
111
|
+
[MarkdownUp Front-End Application](https://github.com/craigahobbs/markdown-up#readme)
|
|
112
|
+
using the
|
|
113
|
+
[BareScript](https://github.com/craigahobbs/bare-script#readme)
|
|
114
|
+
programming language. Markdown files viewed within MarkdownUp may contain `markdown-script` fenced
|
|
115
|
+
code blocks containing
|
|
116
|
+
[BareScript](https://github.com/craigahobbs/bare-script#readme)
|
|
117
|
+
that executes when the Markdown renders.
|
|
118
|
+
|
|
119
|
+
MarkdownUp has libraries for dynamically generating and rendering Markdown text, drawing SVG images,
|
|
120
|
+
performing data analytics, parsing application arguments, and much more. See the
|
|
121
|
+
[MarkdownUp Library](https://craigahobbs.github.io/markdown-up/library/)
|
|
122
|
+
and
|
|
123
|
+
[MarkdownUp Include Library](https://craigahobbs.github.io/markdown-up/library/include.html)
|
|
124
|
+
for more information.
|
|
125
|
+
|
|
126
|
+
Here's an example of a simple MarkdownUp application:
|
|
127
|
+
|
|
128
|
+
~~~markdown
|
|
129
|
+
# The First Ten Numbers
|
|
130
|
+
|
|
131
|
+
Here are the first ten numbers:
|
|
132
|
+
|
|
133
|
+
```markdown-script
|
|
134
|
+
i = 1
|
|
135
|
+
while i <= 10:
|
|
136
|
+
markdownPrint('', stringNew(i))
|
|
137
|
+
i = i + 1
|
|
138
|
+
endwhile
|
|
139
|
+
```
|
|
140
|
+
~~~
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
This package is developed using [python-build](https://github.com/craigahobbs/python-build#readme).
|
|
146
|
+
It was started using [python-template](https://github.com/craigahobbs/python-template#readme) as follows:
|
|
147
|
+
|
|
148
|
+
~~~
|
|
149
|
+
template-specialize python-template/template/ markdown-up-py/ -k package markdown-up -k name 'Craig A. Hobbs' -k email 'craigahobbs@gmail.com' -k github 'craigahobbs' -k noapi 1
|
|
150
|
+
~~~
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# markdown-up
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/markdown-up/)
|
|
4
|
+
[](https://pypi.org/project/markdown-up/)
|
|
5
|
+
[](https://github.com/craigahobbs/markdown-up-py/blob/main/LICENSE)
|
|
6
|
+
[](https://pypi.org/project/markdown-up/)
|
|
7
|
+
|
|
8
|
+
MarkdownUp is a Markdown viewer.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Install MarkdownUp
|
|
12
|
+
|
|
13
|
+
Use Python's `pip` to install MarkdownUp as follows:
|
|
14
|
+
|
|
15
|
+
~~~
|
|
16
|
+
pip install markdown-up
|
|
17
|
+
~~~
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## View Markdown Files
|
|
21
|
+
|
|
22
|
+
To start MarkdownUp, open a terminal and run the `markdown-up` application:
|
|
23
|
+
|
|
24
|
+
~~~
|
|
25
|
+
markdown-up
|
|
26
|
+
~~~
|
|
27
|
+
|
|
28
|
+
The `markdown-up` application opens the web browser to the MarkdownUp file browser, which allows you
|
|
29
|
+
to view Markdown or HTML files and navigate directories. To view a file, click on its link.
|
|
30
|
+
|
|
31
|
+
You can view a specific file as follows:
|
|
32
|
+
|
|
33
|
+
~~~
|
|
34
|
+
markdown-up README.md
|
|
35
|
+
~~~
|
|
36
|
+
|
|
37
|
+
**Note:** MarkdownUp runs entirely offline. It does not use an external service to render Markdown
|
|
38
|
+
files.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## Running MarkdownUp
|
|
42
|
+
|
|
43
|
+
When you run the `markdown-up` application, in addition to opening the web browser, it starts a
|
|
44
|
+
[chisel](https://pypi.org/project/chisel/)
|
|
45
|
+
backend API application using
|
|
46
|
+
[waitress](https://pypi.org/project/waitress/).
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Automatically Creates HTML for Markdown Files
|
|
50
|
+
|
|
51
|
+
When you run MarkdownUp and click on a Markdown file link, the link navigates to an HTML file that
|
|
52
|
+
renders the Markdown file. Every Markdown file hosted by MarkdownUp has a corresponding `.html` file
|
|
53
|
+
of the same name. For example, if you run Markdown up in a directory that has the following Markdown
|
|
54
|
+
files: "README.md" and "CHANGELOG.md". The MarkdownUp service automatically generates "README.html"
|
|
55
|
+
and "CHANGELOG.html" files.
|
|
56
|
+
|
|
57
|
+
The generated `.html` files are HTML stubs for the
|
|
58
|
+
[MarkdownUp Front-End Application](https://github.com/craigahobbs/markdown-up#readme).
|
|
59
|
+
All Markdown parsing and rendering are done on the client to minimize server costs.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
### Command-Line Arguments
|
|
63
|
+
|
|
64
|
+
The `markdown-up` application has the following command-line arguments:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
usage: markdown-up [-h] [-p N] [-t N] [-n] [-r] [-q] [path]
|
|
68
|
+
|
|
69
|
+
positional arguments:
|
|
70
|
+
path the file or directory to view (default is ".")
|
|
71
|
+
|
|
72
|
+
options:
|
|
73
|
+
-h, --help show this help message and exit
|
|
74
|
+
-p N the application port (default is 8080)
|
|
75
|
+
-t N the number of web server threads (default is 8)
|
|
76
|
+
-n don't open a web browser
|
|
77
|
+
-r release mode (cache statics, remove documentation and index)
|
|
78
|
+
-q don't display access logging
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
## MarkdownUp Applications
|
|
83
|
+
|
|
84
|
+
[MarkdownUp Applications](https://github.com/craigahobbs/markdown-up?tab=readme-ov-file#dynamic-markdown-applications)
|
|
85
|
+
are front-end applications that run within the
|
|
86
|
+
[MarkdownUp Front-End Application](https://github.com/craigahobbs/markdown-up#readme)
|
|
87
|
+
using the
|
|
88
|
+
[BareScript](https://github.com/craigahobbs/bare-script#readme)
|
|
89
|
+
programming language. Markdown files viewed within MarkdownUp may contain `markdown-script` fenced
|
|
90
|
+
code blocks containing
|
|
91
|
+
[BareScript](https://github.com/craigahobbs/bare-script#readme)
|
|
92
|
+
that executes when the Markdown renders.
|
|
93
|
+
|
|
94
|
+
MarkdownUp has libraries for dynamically generating and rendering Markdown text, drawing SVG images,
|
|
95
|
+
performing data analytics, parsing application arguments, and much more. See the
|
|
96
|
+
[MarkdownUp Library](https://craigahobbs.github.io/markdown-up/library/)
|
|
97
|
+
and
|
|
98
|
+
[MarkdownUp Include Library](https://craigahobbs.github.io/markdown-up/library/include.html)
|
|
99
|
+
for more information.
|
|
100
|
+
|
|
101
|
+
Here's an example of a simple MarkdownUp application:
|
|
102
|
+
|
|
103
|
+
~~~markdown
|
|
104
|
+
# The First Ten Numbers
|
|
105
|
+
|
|
106
|
+
Here are the first ten numbers:
|
|
107
|
+
|
|
108
|
+
```markdown-script
|
|
109
|
+
i = 1
|
|
110
|
+
while i <= 10:
|
|
111
|
+
markdownPrint('', stringNew(i))
|
|
112
|
+
i = i + 1
|
|
113
|
+
endwhile
|
|
114
|
+
```
|
|
115
|
+
~~~
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
This package is developed using [python-build](https://github.com/craigahobbs/python-build#readme).
|
|
121
|
+
It was started using [python-template](https://github.com/craigahobbs/python-template#readme) as follows:
|
|
122
|
+
|
|
123
|
+
~~~
|
|
124
|
+
template-specialize python-template/template/ markdown-up-py/ -k package markdown-up -k name 'Craig A. Hobbs' -k email 'craigahobbs@gmail.com' -k github 'craigahobbs' -k noapi 1
|
|
125
|
+
~~~
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = markdown-up
|
|
3
|
-
version = 2.
|
|
3
|
+
version = 2.2.0
|
|
4
4
|
url = https://github.com/craigahobbs/markdown-up-py
|
|
5
5
|
author = Craig A. Hobbs
|
|
6
6
|
author_email = craigahobbs@gmail.com
|
|
@@ -26,7 +26,7 @@ packages = markdown_up, markdown_up.static
|
|
|
26
26
|
package_dir =
|
|
27
27
|
= src
|
|
28
28
|
install_requires =
|
|
29
|
-
chisel >= 1.
|
|
29
|
+
chisel >= 1.5.0
|
|
30
30
|
waitress >= 3.0.0
|
|
31
31
|
|
|
32
32
|
[options.entry_points]
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# Licensed under the MIT License
|
|
2
|
+
# https://github.com/craigahobbs/markdown-up-py/blob/main/LICENSE
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The MarkdownUp launcher back-end application
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import importlib.resources
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import PurePosixPath
|
|
11
|
+
import threading
|
|
12
|
+
import urllib.parse
|
|
13
|
+
|
|
14
|
+
import chisel
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MarkdownUpApplication(chisel.Application):
|
|
18
|
+
"""
|
|
19
|
+
The markdown-up back-end API WSGI application class
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
__slots__ = ('root', 'release', 'add_request_lock')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def __init__(self, root, release=False):
|
|
26
|
+
super().__init__()
|
|
27
|
+
self.root = root
|
|
28
|
+
self.release = release
|
|
29
|
+
self.add_request_lock = threading.Lock()
|
|
30
|
+
|
|
31
|
+
if release:
|
|
32
|
+
# Add the MarkdownUp application
|
|
33
|
+
self.add_requests(chisel.create_doc_requests(api=False, app=False, markdown_up=True))
|
|
34
|
+
else:
|
|
35
|
+
# Add the chisel documentation application (and the MarkdownUp application)
|
|
36
|
+
self.add_requests(chisel.create_doc_requests())
|
|
37
|
+
|
|
38
|
+
# Add the markdown-up APIs
|
|
39
|
+
self.add_request(markdown_up_index)
|
|
40
|
+
|
|
41
|
+
# Add the markdown-up statics
|
|
42
|
+
self.add_static('index.html', content_type='text/html; charset=utf-8', urls=(('GET', '/'),))
|
|
43
|
+
self.add_static('markdownUpIndex.bare')
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def add_static(self, filename, content_type=None, urls=(('GET', None),), doc_group='MarkdownUp Index Statics'):
|
|
47
|
+
with importlib.resources.files('markdown_up.static').joinpath(filename).open('rb') as fh:
|
|
48
|
+
self.add_request(chisel.StaticRequest(filename, fh.read(), content_type=content_type, urls=urls, doc_group=doc_group))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def __call__(self, environ, start_response):
|
|
52
|
+
request_method = environ['REQUEST_METHOD']
|
|
53
|
+
path_info = environ['PATH_INFO']
|
|
54
|
+
|
|
55
|
+
# Chisel API request? Otherwise, its a static request...
|
|
56
|
+
request, _ = self.match_request(request_method, path_info)
|
|
57
|
+
if request is not None:
|
|
58
|
+
return super().__call__(environ, start_response)
|
|
59
|
+
|
|
60
|
+
# Compute the static file path
|
|
61
|
+
posix_path_info = PurePosixPath(path_info)
|
|
62
|
+
path = os.path.join(self.root, *posix_path_info.parts[1:])
|
|
63
|
+
|
|
64
|
+
# Directory path?
|
|
65
|
+
request = None
|
|
66
|
+
if os.path.isdir(path):
|
|
67
|
+
|
|
68
|
+
# Directory redirect?
|
|
69
|
+
if not path_info.endswith('/'):
|
|
70
|
+
request = chisel.RedirectRequest(((None, path_info),), path_info + '/', name=path_info)
|
|
71
|
+
|
|
72
|
+
# HTML index file exist?
|
|
73
|
+
if request is None:
|
|
74
|
+
for index_file in INDEX_FILES:
|
|
75
|
+
index_posix_path = posix_path_info.joinpath(index_file)
|
|
76
|
+
index_path = os.path.join(self.root, *index_posix_path.parts[1:])
|
|
77
|
+
if os.path.isfile(index_path):
|
|
78
|
+
with open(index_path, 'rb') as index_file:
|
|
79
|
+
request = chisel.StaticRequest(
|
|
80
|
+
path_info,
|
|
81
|
+
index_file.read(),
|
|
82
|
+
content_type='text/html; charset=utf-8',
|
|
83
|
+
urls=(('GET', path_info),)
|
|
84
|
+
)
|
|
85
|
+
break
|
|
86
|
+
|
|
87
|
+
# No HTML index file - does a Markdown index file exist?
|
|
88
|
+
if request is None:
|
|
89
|
+
for index_markdown in INDEX_MARKDOWN:
|
|
90
|
+
markdown_posix_path = posix_path_info.joinpath(index_markdown)
|
|
91
|
+
markdown_path = os.path.join(self.root, *markdown_posix_path.parts[1:])
|
|
92
|
+
if os.path.isfile(markdown_path):
|
|
93
|
+
request = chisel.StaticRequest(
|
|
94
|
+
path_info,
|
|
95
|
+
create_markdown_up_stub(markdown_posix_path.name),
|
|
96
|
+
content_type='text/html; charset=utf-8',
|
|
97
|
+
urls=(('GET', path_info),)
|
|
98
|
+
)
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
# File path?
|
|
102
|
+
elif os.path.isfile(path):
|
|
103
|
+
try:
|
|
104
|
+
with open(path, 'rb') as path_file:
|
|
105
|
+
request = chisel.StaticRequest(path_info, path_file.read(), urls=(('GET', path_info),))
|
|
106
|
+
except AssertionError as exc:
|
|
107
|
+
ctx = chisel.Context(self, environ, start_response)
|
|
108
|
+
ctx.log.warning(str(exc))
|
|
109
|
+
|
|
110
|
+
# Auto-generate MarkdownUp HTML stub?
|
|
111
|
+
elif posix_path_info.suffix == HTML_EXTS[0]:
|
|
112
|
+
for markdown_ext in MARKDOWN_EXTS:
|
|
113
|
+
markdown_posix_path = posix_path_info.with_suffix(markdown_ext)
|
|
114
|
+
markdown_path = os.path.join(self.root, *markdown_posix_path.parts[1:])
|
|
115
|
+
if os.path.isfile(markdown_path):
|
|
116
|
+
request = chisel.StaticRequest(
|
|
117
|
+
path_info,
|
|
118
|
+
create_markdown_up_stub(markdown_posix_path.name),
|
|
119
|
+
content_type='text/html; charset=utf-8',
|
|
120
|
+
urls=(('GET', path_info),)
|
|
121
|
+
)
|
|
122
|
+
break
|
|
123
|
+
|
|
124
|
+
# Not found?
|
|
125
|
+
if not request:
|
|
126
|
+
start_response('404 Not Found', [('Content-Type', 'text/plain; charset=utf-8')])
|
|
127
|
+
return [b'Not Found']
|
|
128
|
+
|
|
129
|
+
# Add the request, if caching of statics is enabled
|
|
130
|
+
if self.release:
|
|
131
|
+
with self.add_request_lock:
|
|
132
|
+
request_lock, _ = self.match_request('GET', path_info)
|
|
133
|
+
if request_lock is None:
|
|
134
|
+
self.add_request(request)
|
|
135
|
+
|
|
136
|
+
# Bad method?
|
|
137
|
+
if isinstance(request, chisel.StaticRequest) and request_method != 'GET':
|
|
138
|
+
start_response('405 Method Not Allowed', [('Content-Type', 'text/plain; charset=utf-8')])
|
|
139
|
+
return [b'Method Not Allowed']
|
|
140
|
+
|
|
141
|
+
# Handle the request
|
|
142
|
+
return request(environ, start_response)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Render-able file extensions
|
|
146
|
+
MARKDOWN_EXTS = ('.md', '.markdown')
|
|
147
|
+
HTML_EXTS = ('.html', '.htm')
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# Index file names
|
|
151
|
+
INDEX_FILES = ('index.html', 'index.htm')
|
|
152
|
+
INDEX_MARKDOWN = ('index.md', 'README.md')
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def create_markdown_up_stub(filename):
|
|
156
|
+
return f'''\
|
|
157
|
+
<!DOCTYPE html>
|
|
158
|
+
<html lang="en">
|
|
159
|
+
<head>
|
|
160
|
+
<title>MarkdownUp</title>
|
|
161
|
+
<meta charset="UTF-8">
|
|
162
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
163
|
+
<link rel="stylesheet" href="/markdown-up/app.css">
|
|
164
|
+
|
|
165
|
+
<!-- Preloads -->
|
|
166
|
+
<link rel="modulepreload" href="/markdown-up/bare-script/lib/data.js" as="script">
|
|
167
|
+
<link rel="modulepreload" href="/markdown-up/bare-script/lib/library.js" as="script">
|
|
168
|
+
<link rel="modulepreload" href="/markdown-up/bare-script/lib/model.js" as="script">
|
|
169
|
+
<link rel="modulepreload" href="/markdown-up/bare-script/lib/options.js" as="script">
|
|
170
|
+
<link rel="modulepreload" href="/markdown-up/bare-script/lib/parser.js" as="script">
|
|
171
|
+
<link rel="modulepreload" href="/markdown-up/bare-script/lib/runtime.js" as="script">
|
|
172
|
+
<link rel="modulepreload" href="/markdown-up/bare-script/lib/runtimeAsync.js" as="script">
|
|
173
|
+
<link rel="modulepreload" href="/markdown-up/bare-script/lib/value.js" as="script">
|
|
174
|
+
<link rel="modulepreload" href="/markdown-up/element-model/lib/elementModel.js" as="script">
|
|
175
|
+
<link rel="modulepreload" href="/markdown-up/lib/app.js" as="script">
|
|
176
|
+
<link rel="modulepreload" href="/markdown-up/lib/dataTable.js" as="script">
|
|
177
|
+
<link rel="modulepreload" href="/markdown-up/lib/dataUtil.js" as="script">
|
|
178
|
+
<link rel="modulepreload" href="/markdown-up/lib/lineChart.js" as="script">
|
|
179
|
+
<link rel="modulepreload" href="/markdown-up/lib/script.js" as="script">
|
|
180
|
+
<link rel="modulepreload" href="/markdown-up/lib/scriptLibrary.js" as="script">
|
|
181
|
+
<link rel="modulepreload" href="/markdown-up/markdown-model/lib/elements.js" as="script">
|
|
182
|
+
<link rel="modulepreload" href="/markdown-up/markdown-model/lib/highlight.js" as="script">
|
|
183
|
+
<link rel="modulepreload" href="/markdown-up/markdown-model/lib/parser.js" as="script">
|
|
184
|
+
<link rel="modulepreload" href="/markdown-up/schema-markdown-doc/lib/schemaMarkdownDoc.js" as="script">
|
|
185
|
+
<link rel="modulepreload" href="/markdown-up/schema-markdown/lib/encode.js" as="script">
|
|
186
|
+
<link rel="modulepreload" href="/markdown-up/schema-markdown/lib/parser.js" as="script">
|
|
187
|
+
<link rel="modulepreload" href="/markdown-up/schema-markdown/lib/schema.js" as="script">
|
|
188
|
+
<link rel="modulepreload" href="/markdown-up/schema-markdown/lib/schemaUtil.js" as="script">
|
|
189
|
+
<link rel="modulepreload" href="/markdown-up/schema-markdown/lib/typeModel.js" as="script">
|
|
190
|
+
<link rel="preload" href="/markdown-up/app.css" as="style">
|
|
191
|
+
<link rel="preload" href="/markdown-up/markdown-model/static/markdown-model.css" as="style">
|
|
192
|
+
</head>
|
|
193
|
+
<body>
|
|
194
|
+
</body>
|
|
195
|
+
<script type="module">
|
|
196
|
+
import {{MarkdownUp}} from '/markdown-up/lib/app.js';
|
|
197
|
+
const app = new MarkdownUp(window, {{
|
|
198
|
+
'systemPrefix': '/markdown-up/include/',
|
|
199
|
+
'url': '{urllib.parse.quote(filename)}'
|
|
200
|
+
}});
|
|
201
|
+
app.run();
|
|
202
|
+
</script>
|
|
203
|
+
</html>
|
|
204
|
+
'''.encode('utf-8')
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@chisel.action(spec='''\
|
|
208
|
+
group "MarkdownUp Index API"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# The MarkdownUp launcher index API
|
|
212
|
+
action markdown_up_index
|
|
213
|
+
urls
|
|
214
|
+
GET
|
|
215
|
+
|
|
216
|
+
query
|
|
217
|
+
# The relative sub-directory path
|
|
218
|
+
optional string(len > 0) path
|
|
219
|
+
|
|
220
|
+
output
|
|
221
|
+
# The index path
|
|
222
|
+
string path
|
|
223
|
+
|
|
224
|
+
# The parent path
|
|
225
|
+
optional string parent
|
|
226
|
+
|
|
227
|
+
# The path's files
|
|
228
|
+
IndexFile[] files
|
|
229
|
+
|
|
230
|
+
# The path's sub-directories
|
|
231
|
+
string[] directories
|
|
232
|
+
|
|
233
|
+
errors
|
|
234
|
+
# The path is invalid
|
|
235
|
+
InvalidPath
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# An index file
|
|
239
|
+
struct IndexFile
|
|
240
|
+
|
|
241
|
+
# The file name
|
|
242
|
+
string name
|
|
243
|
+
|
|
244
|
+
# The file's display name
|
|
245
|
+
optional string display
|
|
246
|
+
''')
|
|
247
|
+
def markdown_up_index(ctx, req):
|
|
248
|
+
# Validate the path
|
|
249
|
+
posix_path = PurePosixPath(req['path'] if 'path' in req else '')
|
|
250
|
+
if posix_path.is_absolute() or any(part == '..' for part in posix_path.parts):
|
|
251
|
+
raise chisel.ActionError('InvalidPath')
|
|
252
|
+
|
|
253
|
+
# Verify that the path exists
|
|
254
|
+
path = os.path.join(ctx.app.root, *posix_path.parts)
|
|
255
|
+
if not os.path.isdir(path):
|
|
256
|
+
raise chisel.ActionError('InvalidPath')
|
|
257
|
+
|
|
258
|
+
# Compute parent path
|
|
259
|
+
parent_path = str(posix_path.parent) if 'path' in req else None
|
|
260
|
+
|
|
261
|
+
# Get the list of files and sub-directories from the current sub-directory
|
|
262
|
+
files = []
|
|
263
|
+
directories = []
|
|
264
|
+
for entry in os.scandir(path):
|
|
265
|
+
if entry.is_file():
|
|
266
|
+
# Markdown files are viewed using their generated MarkdownUp HTML stubs
|
|
267
|
+
name_root, name_ext = os.path.splitext(entry.name)
|
|
268
|
+
if name_ext in MARKDOWN_EXTS:
|
|
269
|
+
files.append({'name': f'{name_root}{HTML_EXTS[0]}', 'display': entry.name})
|
|
270
|
+
elif name_ext in HTML_EXTS:
|
|
271
|
+
files.append({'name': entry.name})
|
|
272
|
+
elif entry.is_dir(): # pragma: no branch
|
|
273
|
+
directories.append(entry.name)
|
|
274
|
+
|
|
275
|
+
# Return the response
|
|
276
|
+
response = {
|
|
277
|
+
'path': path,
|
|
278
|
+
'files': sorted(files, key=lambda file_: file_.get('display', file_['name'])),
|
|
279
|
+
'directories': sorted(directories)
|
|
280
|
+
}
|
|
281
|
+
if parent_path is not None and parent_path != '.':
|
|
282
|
+
response['parent'] = parent_path
|
|
283
|
+
return response
|
|
@@ -6,14 +6,14 @@ The MarkdownUp launcher command-line application
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import argparse
|
|
9
|
+
from functools import partial
|
|
9
10
|
import os
|
|
10
11
|
import threading
|
|
11
12
|
import webbrowser
|
|
12
13
|
|
|
13
|
-
from schema_markdown import encode_query_string
|
|
14
14
|
import waitress
|
|
15
15
|
|
|
16
|
-
from .app import HTML_EXTS, MarkdownUpApplication
|
|
16
|
+
from .app import HTML_EXTS, MARKDOWN_EXTS, MarkdownUpApplication
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def main(argv=None):
|
|
@@ -24,11 +24,15 @@ def main(argv=None):
|
|
|
24
24
|
# Command line arguments
|
|
25
25
|
parser = argparse.ArgumentParser(prog='markdown-up')
|
|
26
26
|
parser.add_argument('path', nargs='?', default='.',
|
|
27
|
-
help='the
|
|
27
|
+
help='the file or directory to view (default is ".")')
|
|
28
28
|
parser.add_argument('-p', metavar='N', dest='port', type=int, default=8080,
|
|
29
29
|
help='the application port (default is 8080)')
|
|
30
|
+
parser.add_argument('-t', metavar='N', dest='threads', type=int, default=8,
|
|
31
|
+
help='the number of web server threads (default is 8)')
|
|
30
32
|
parser.add_argument('-n', dest='no_browser', action='store_true',
|
|
31
33
|
help="don't open a web browser")
|
|
34
|
+
parser.add_argument('-r', dest='release', action='store_true',
|
|
35
|
+
help="release mode (cache statics, remove documentation and index)")
|
|
32
36
|
parser.add_argument('-q', dest='quiet', action='store_true',
|
|
33
37
|
help="don't display access logging")
|
|
34
38
|
args = parser.parse_args(args=argv)
|
|
@@ -52,11 +56,12 @@ def main(argv=None):
|
|
|
52
56
|
# Construct the URL
|
|
53
57
|
host = '127.0.0.1'
|
|
54
58
|
if is_file:
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
path_base = os.path.basename(args.path)
|
|
60
|
+
path_root, path_ext = os.path.splitext(path_base)
|
|
61
|
+
if path_ext in MARKDOWN_EXTS:
|
|
62
|
+
url = f'http://{host}:{args.port}/{path_root}{HTML_EXTS[0]}'
|
|
57
63
|
else:
|
|
58
|
-
|
|
59
|
-
url = f'http://{host}:{args.port}/#{hash_args}'
|
|
64
|
+
url = f'http://{host}:{args.port}/{path_base}'
|
|
60
65
|
else:
|
|
61
66
|
url = f'http://{host}:{args.port}/'
|
|
62
67
|
|
|
@@ -67,17 +72,18 @@ def main(argv=None):
|
|
|
67
72
|
webbrowser_thread.start()
|
|
68
73
|
|
|
69
74
|
# Create the WSGI application
|
|
70
|
-
wsgiapp = MarkdownUpApplication(root)
|
|
71
|
-
|
|
72
|
-
# Wrap the WSGI application and the start_response function so we can log status and environ
|
|
73
|
-
def wsgiapp_wrap(environ, start_response):
|
|
74
|
-
def log_start_response(status, response_headers):
|
|
75
|
-
if not args.quiet:
|
|
76
|
-
print(f'markdown-up: {status[0:3]} {environ["REQUEST_METHOD"]} {environ["PATH_INFO"]} {environ["QUERY_STRING"]}')
|
|
77
|
-
return start_response(status, response_headers)
|
|
78
|
-
return wsgiapp(environ, log_start_response)
|
|
75
|
+
wsgiapp = MarkdownUpApplication(root, args.release)
|
|
76
|
+
wsgiapp_wrap = wsgiapp if args.quiet else partial(_wsgiapp_log_access, wsgiapp)
|
|
79
77
|
|
|
80
78
|
# Host the application
|
|
81
79
|
if not args.quiet:
|
|
82
80
|
print(f'markdown-up: Serving at {url} ...')
|
|
83
|
-
waitress.serve(wsgiapp_wrap, port=args.port)
|
|
81
|
+
waitress.serve(wsgiapp_wrap, port=args.port, threads=max(args.threads, 1))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# WSGI application wrapper and the start_response function so we can log status and environ
|
|
85
|
+
def _wsgiapp_log_access(wsgiapp, environ, start_response):
|
|
86
|
+
def log_start_response(status, response_headers):
|
|
87
|
+
print(f'markdown-up: {status[0:3]} {environ["REQUEST_METHOD"]} {environ["PATH_INFO"]} {environ["QUERY_STRING"]}')
|
|
88
|
+
return start_response(status, response_headers)
|
|
89
|
+
return wsgiapp(environ, log_start_response)
|