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.
Files changed (23) hide show
  1. markdown_up-2.2.0/PKG-INFO +150 -0
  2. markdown_up-2.2.0/README.md +125 -0
  3. {markdown_up-2.1.4 → markdown_up-2.2.0}/setup.cfg +2 -2
  4. markdown_up-2.2.0/src/markdown_up/app.py +283 -0
  5. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/main.py +23 -17
  6. markdown_up-2.2.0/src/markdown_up/static/index.html +54 -0
  7. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/static/markdownUpIndex.bare +17 -19
  8. markdown_up-2.2.0/src/markdown_up.egg-info/PKG-INFO +150 -0
  9. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/requires.txt +1 -1
  10. markdown_up-2.1.4/PKG-INFO +0 -63
  11. markdown_up-2.1.4/README.md +0 -38
  12. markdown_up-2.1.4/src/markdown_up/app.py +0 -207
  13. markdown_up-2.1.4/src/markdown_up/static/index.html +0 -54
  14. markdown_up-2.1.4/src/markdown_up.egg-info/PKG-INFO +0 -63
  15. {markdown_up-2.1.4 → markdown_up-2.2.0}/LICENSE +0 -0
  16. {markdown_up-2.1.4 → markdown_up-2.2.0}/pyproject.toml +0 -0
  17. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/__init__.py +0 -0
  18. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/__main__.py +0 -0
  19. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up/static/__init__.py +0 -0
  20. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/SOURCES.txt +0 -0
  21. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/dependency_links.txt +0 -0
  22. {markdown_up-2.1.4 → markdown_up-2.2.0}/src/markdown_up.egg-info/entry_points.txt +0 -0
  23. {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
+ [![PyPI - Status](https://img.shields.io/pypi/status/markdown-up)](https://pypi.org/project/markdown-up/)
29
+ [![PyPI](https://img.shields.io/pypi/v/markdown-up)](https://pypi.org/project/markdown-up/)
30
+ [![GitHub](https://img.shields.io/github/license/craigahobbs/markdown-up-py)](https://github.com/craigahobbs/markdown-up-py/blob/main/LICENSE)
31
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/markdown-up)](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
+ [![PyPI - Status](https://img.shields.io/pypi/status/markdown-up)](https://pypi.org/project/markdown-up/)
4
+ [![PyPI](https://img.shields.io/pypi/v/markdown-up)](https://pypi.org/project/markdown-up/)
5
+ [![GitHub](https://img.shields.io/github/license/craigahobbs/markdown-up-py)](https://github.com/craigahobbs/markdown-up-py/blob/main/LICENSE)
6
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/markdown-up)](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.1.4
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.4.6
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 markdown file or directory to view (default is ".")')
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
- if args.path.endswith(HTML_EXTS):
56
- url = f'http://{host}:{args.port}/{os.path.basename(args.path)}'
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
- hash_args = encode_query_string({'url': os.path.basename(args.path)})
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)