mdok 0.1.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.
- mdok-0.1.0/LICENSE +21 -0
- mdok-0.1.0/PKG-INFO +97 -0
- mdok-0.1.0/README.md +63 -0
- mdok-0.1.0/pyproject.toml +61 -0
- mdok-0.1.0/setup.cfg +4 -0
- mdok-0.1.0/src/mdok/__init__.py +4 -0
- mdok-0.1.0/src/mdok/__main__.py +4 -0
- mdok-0.1.0/src/mdok/canvas.py +102 -0
- mdok-0.1.0/src/mdok/cli.py +169 -0
- mdok-0.1.0/src/mdok/renderer.py +632 -0
- mdok-0.1.0/src/mdok/theme.py +39 -0
- mdok-0.1.0/src/mdok.egg-info/PKG-INFO +97 -0
- mdok-0.1.0/src/mdok.egg-info/SOURCES.txt +23 -0
- mdok-0.1.0/src/mdok.egg-info/dependency_links.txt +1 -0
- mdok-0.1.0/src/mdok.egg-info/entry_points.txt +3 -0
- mdok-0.1.0/src/mdok.egg-info/requires.txt +6 -0
- mdok-0.1.0/src/mdok.egg-info/top_level.txt +1 -0
- mdok-0.1.0/tests/test_br.py +67 -0
- mdok-0.1.0/tests/test_callouts.py +23 -0
- mdok-0.1.0/tests/test_canvas.py +59 -0
- mdok-0.1.0/tests/test_cli.py +38 -0
- mdok-0.1.0/tests/test_multiline_table.py +43 -0
- mdok-0.1.0/tests/test_smart_table.py +373 -0
- mdok-0.1.0/tests/test_tables.py +57 -0
- mdok-0.1.0/tests/test_theme.py +38 -0
mdok-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Anton
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mdok-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mdok
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A document-grade terminal markdown reader with responsive centering and clean tables
|
|
5
|
+
Author: Anton
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/anton/mdok
|
|
8
|
+
Project-URL: Repository, https://github.com/anton/mdok
|
|
9
|
+
Project-URL: Issues, https://github.com/anton/mdok/issues
|
|
10
|
+
Keywords: markdown,terminal,cli,reader,rich,viewer,booktabs
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: rich>=13.0.0
|
|
29
|
+
Requires-Dist: markdown-it-py>=3.0.0
|
|
30
|
+
Requires-Dist: pygments>=2.15.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# mdok
|
|
36
|
+
|
|
37
|
+
A small CLI tool for reading Markdown files in the terminal.
|
|
38
|
+
|
|
39
|
+
Most terminal renderers either stretch text across the entire display width or force it into a rigid, narrow column on the left edge. Tables often fuse rows together, eat technical tags like `<Type>`, or ignore `<br>` line breaks.
|
|
40
|
+
|
|
41
|
+
`mdok` formats Markdown like a clean document:
|
|
42
|
+
|
|
43
|
+
- **Proportional width & centering**: Centers text on wide displays with gentle margins and scales comfortably (~75% of terminal width up to ~120 columns).
|
|
44
|
+
- **Readable tables**: LaTeX *booktabs* style—horizontal rules, no heavy ASCII borders, soft cell wrapping, alignment support, and row dividers so multiline rows don't run together.
|
|
45
|
+
- **Tag & line break handling**: Preserves technical tags (like `<Tag>` or `<Property>`) and respects `<br>` breaks inside cells.
|
|
46
|
+
- **Muted colors**: Inline code uses a warm amber (`#e0af68`) on a subtle dark badge instead of bright yellow. Code blocks default to the Nord syntax theme.
|
|
47
|
+
- **Automatic pager**: Pipes into `less` (with colors preserved) when the document is longer than your terminal screen.
|
|
48
|
+
- **GitHub-style callouts**: Renders `> [!NOTE]`, `> [!TIP]`, `> [!WARNING]`, etc.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install mdok
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or from source:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/anton/mdok.git
|
|
62
|
+
cd mdok
|
|
63
|
+
pip install .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
For development:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install -e .
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
Read a file:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
mdok README.md
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Pipe from standard input:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
cat doc.md | mdok
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Options
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
mdok doc.md -w 100 # Explicit document width in columns
|
|
92
|
+
mdok doc.md -m 4 # Explicit left margin
|
|
93
|
+
mdok doc.md --no-center # Align to left edge
|
|
94
|
+
mdok doc.md -b rounded # Table style (booktabs, rounded, simple, minimal, none)
|
|
95
|
+
mdok doc.md --code-theme gruvbox-dark # Syntax highlighting theme
|
|
96
|
+
mdok doc.md --no-pager # Print directly without pager
|
|
97
|
+
```
|
mdok-0.1.0/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# mdok
|
|
2
|
+
|
|
3
|
+
A small CLI tool for reading Markdown files in the terminal.
|
|
4
|
+
|
|
5
|
+
Most terminal renderers either stretch text across the entire display width or force it into a rigid, narrow column on the left edge. Tables often fuse rows together, eat technical tags like `<Type>`, or ignore `<br>` line breaks.
|
|
6
|
+
|
|
7
|
+
`mdok` formats Markdown like a clean document:
|
|
8
|
+
|
|
9
|
+
- **Proportional width & centering**: Centers text on wide displays with gentle margins and scales comfortably (~75% of terminal width up to ~120 columns).
|
|
10
|
+
- **Readable tables**: LaTeX *booktabs* style—horizontal rules, no heavy ASCII borders, soft cell wrapping, alignment support, and row dividers so multiline rows don't run together.
|
|
11
|
+
- **Tag & line break handling**: Preserves technical tags (like `<Tag>` or `<Property>`) and respects `<br>` breaks inside cells.
|
|
12
|
+
- **Muted colors**: Inline code uses a warm amber (`#e0af68`) on a subtle dark badge instead of bright yellow. Code blocks default to the Nord syntax theme.
|
|
13
|
+
- **Automatic pager**: Pipes into `less` (with colors preserved) when the document is longer than your terminal screen.
|
|
14
|
+
- **GitHub-style callouts**: Renders `> [!NOTE]`, `> [!TIP]`, `> [!WARNING]`, etc.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install mdok
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or from source:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
git clone https://github.com/anton/mdok.git
|
|
28
|
+
cd mdok
|
|
29
|
+
pip install .
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For development:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
Read a file:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
mdok README.md
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Pipe from standard input:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cat doc.md | mdok
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Options
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
mdok doc.md -w 100 # Explicit document width in columns
|
|
58
|
+
mdok doc.md -m 4 # Explicit left margin
|
|
59
|
+
mdok doc.md --no-center # Align to left edge
|
|
60
|
+
mdok doc.md -b rounded # Table style (booktabs, rounded, simple, minimal, none)
|
|
61
|
+
mdok doc.md --code-theme gruvbox-dark # Syntax highlighting theme
|
|
62
|
+
mdok doc.md --no-pager # Print directly without pager
|
|
63
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mdok"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A document-grade terminal markdown reader with responsive centering and clean tables"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Anton" }
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"markdown",
|
|
17
|
+
"terminal",
|
|
18
|
+
"cli",
|
|
19
|
+
"reader",
|
|
20
|
+
"rich",
|
|
21
|
+
"viewer",
|
|
22
|
+
"booktabs",
|
|
23
|
+
]
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Development Status :: 4 - Beta",
|
|
26
|
+
"Environment :: Console",
|
|
27
|
+
"Intended Audience :: Developers",
|
|
28
|
+
"Intended Audience :: End Users/Desktop",
|
|
29
|
+
"Operating System :: OS Independent",
|
|
30
|
+
"Programming Language :: Python :: 3",
|
|
31
|
+
"Programming Language :: Python :: 3.9",
|
|
32
|
+
"Programming Language :: Python :: 3.10",
|
|
33
|
+
"Programming Language :: Python :: 3.11",
|
|
34
|
+
"Programming Language :: Python :: 3.12",
|
|
35
|
+
"Programming Language :: Python :: 3.13",
|
|
36
|
+
"Programming Language :: Python :: 3.14",
|
|
37
|
+
"Topic :: Text Processing :: Markup :: Markdown",
|
|
38
|
+
"Topic :: Utilities",
|
|
39
|
+
]
|
|
40
|
+
dependencies = [
|
|
41
|
+
"rich>=13.0.0",
|
|
42
|
+
"markdown-it-py>=3.0.0",
|
|
43
|
+
"pygments>=2.15.0",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"pytest>=7.0.0",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.scripts]
|
|
52
|
+
mdok = "mdok.cli:main"
|
|
53
|
+
mda = "mdok.cli:main"
|
|
54
|
+
|
|
55
|
+
[project.urls]
|
|
56
|
+
Homepage = "https://github.com/anton/mdok"
|
|
57
|
+
Repository = "https://github.com/anton/mdok"
|
|
58
|
+
Issues = "https://github.com/anton/mdok/issues"
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.packages.find]
|
|
61
|
+
where = ["src"]
|
mdok-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Optional, Tuple
|
|
4
|
+
from rich.console import Console, ConsoleOptions, RenderResult, RenderableType
|
|
5
|
+
from rich.segment import Segment
|
|
6
|
+
from rich.measure import Measurement
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class CanvasConfig:
|
|
11
|
+
"""Configuration for document canvas layout."""
|
|
12
|
+
max_width: Optional[int] = None
|
|
13
|
+
min_width: int = 70
|
|
14
|
+
cap_width: int = 124
|
|
15
|
+
ratio: float = 0.74
|
|
16
|
+
margin: Optional[int] = None
|
|
17
|
+
center: bool = True
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def calculate_dimensions(
|
|
21
|
+
terminal_width: int,
|
|
22
|
+
config: Optional[CanvasConfig] = None,
|
|
23
|
+
) -> Tuple[int, int]:
|
|
24
|
+
"""
|
|
25
|
+
Calculate (doc_width, left_margin) based on terminal width and config.
|
|
26
|
+
|
|
27
|
+
Rules:
|
|
28
|
+
- Narrow screens (<= 82): maximize width with minimal 2-char gutter.
|
|
29
|
+
- Medium screens (83-105): generous 80-85% width.
|
|
30
|
+
- Wide screens (> 105): proportional document sheet (~74% width) up to cap_width (default 124),
|
|
31
|
+
avoiding both full-screen blowout and artificial narrow text walls.
|
|
32
|
+
"""
|
|
33
|
+
cfg = config or CanvasConfig()
|
|
34
|
+
|
|
35
|
+
if cfg.max_width is not None:
|
|
36
|
+
doc_w = min(cfg.max_width, terminal_width)
|
|
37
|
+
else:
|
|
38
|
+
if terminal_width <= 82:
|
|
39
|
+
doc_w = max(30, terminal_width - 4)
|
|
40
|
+
elif terminal_width <= 105:
|
|
41
|
+
doc_w = min(terminal_width - 6, max(76, int(terminal_width * 0.84)))
|
|
42
|
+
else:
|
|
43
|
+
proportional = int(terminal_width * cfg.ratio)
|
|
44
|
+
doc_w = min(cfg.cap_width, max(88, proportional))
|
|
45
|
+
doc_w = min(doc_w, terminal_width - 12)
|
|
46
|
+
|
|
47
|
+
doc_w = max(20, min(doc_w, terminal_width))
|
|
48
|
+
|
|
49
|
+
if cfg.margin is not None:
|
|
50
|
+
left_margin = max(0, min(cfg.margin, terminal_width - doc_w))
|
|
51
|
+
elif cfg.center:
|
|
52
|
+
left_margin = max(0, (terminal_width - doc_w) // 2)
|
|
53
|
+
else:
|
|
54
|
+
left_margin = 0
|
|
55
|
+
|
|
56
|
+
return doc_w, left_margin
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class DocumentCanvas:
|
|
60
|
+
"""
|
|
61
|
+
Renders a renderable constrained to `doc_width` and indented by `left_margin`.
|
|
62
|
+
This provides a centered 'sheet of paper' reading experience.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(
|
|
66
|
+
self,
|
|
67
|
+
renderable: RenderableType,
|
|
68
|
+
doc_width: int,
|
|
69
|
+
left_margin: int,
|
|
70
|
+
) -> None:
|
|
71
|
+
self.renderable = renderable
|
|
72
|
+
self.doc_width = doc_width
|
|
73
|
+
self.left_margin = left_margin
|
|
74
|
+
|
|
75
|
+
def __rich_console__(
|
|
76
|
+
self, console: Console, options: ConsoleOptions
|
|
77
|
+
) -> RenderResult:
|
|
78
|
+
if getattr(self.renderable, "has_canvas_layout", False):
|
|
79
|
+
# Renderable manages its own margins and widths (including table breakout)
|
|
80
|
+
yield from console.render(self.renderable, options)
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
# Constrain the inner document to doc_width
|
|
84
|
+
doc_options = options.update_width(self.doc_width)
|
|
85
|
+
lines = console.render_lines(self.renderable, doc_options, pad=False)
|
|
86
|
+
|
|
87
|
+
margin_prefix = " " * self.left_margin if self.left_margin > 0 else ""
|
|
88
|
+
margin_segment = Segment(margin_prefix) if margin_prefix else None
|
|
89
|
+
|
|
90
|
+
for line in lines:
|
|
91
|
+
if margin_segment and line:
|
|
92
|
+
yield margin_segment
|
|
93
|
+
for segment in line:
|
|
94
|
+
yield segment
|
|
95
|
+
yield Segment.line()
|
|
96
|
+
elif margin_segment and not line:
|
|
97
|
+
# Blank line
|
|
98
|
+
yield Segment.line()
|
|
99
|
+
else:
|
|
100
|
+
for segment in line:
|
|
101
|
+
yield segment
|
|
102
|
+
yield Segment.line()
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from typing import Optional, List
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.theme import Theme
|
|
8
|
+
|
|
9
|
+
from mdok import __version__
|
|
10
|
+
from mdok.theme import DEFAULT_THEME, BOX_STYLES
|
|
11
|
+
from mdok.canvas import CanvasConfig, calculate_dimensions, DocumentCanvas
|
|
12
|
+
from mdok.renderer import DocMarkdown
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_args(args: Optional[List[str]] = None) -> argparse.Namespace:
|
|
16
|
+
parser = argparse.ArgumentParser(
|
|
17
|
+
prog="mdok",
|
|
18
|
+
description="Document-grade Markdown Reader for the terminal.",
|
|
19
|
+
)
|
|
20
|
+
parser.add_argument(
|
|
21
|
+
"file",
|
|
22
|
+
nargs="?",
|
|
23
|
+
default="-",
|
|
24
|
+
help="Markdown file to read, or '-' for standard input (default: '-')",
|
|
25
|
+
)
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"-w",
|
|
28
|
+
"--width",
|
|
29
|
+
type=int,
|
|
30
|
+
default=None,
|
|
31
|
+
help="Max document reading width (default: auto ~88 chars on wide displays)",
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"-m",
|
|
35
|
+
"--margin",
|
|
36
|
+
type=int,
|
|
37
|
+
default=None,
|
|
38
|
+
help="Explicit left margin in columns (default: auto-centered)",
|
|
39
|
+
)
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--no-center",
|
|
42
|
+
action="store_true",
|
|
43
|
+
help="Disable centering and align to left edge",
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"-b",
|
|
47
|
+
"--box",
|
|
48
|
+
choices=list(BOX_STYLES.keys()),
|
|
49
|
+
default="booktabs",
|
|
50
|
+
help="Table box style: booktabs (default), minimal, rounded, simple, simple_head, none",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--no-lines",
|
|
54
|
+
action="store_true",
|
|
55
|
+
help="Hide horizontal row divider lines in tables",
|
|
56
|
+
)
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"--code-theme",
|
|
59
|
+
default="nord",
|
|
60
|
+
help="Pygments code syntax highlighting theme (default: nord)",
|
|
61
|
+
)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
"-p",
|
|
64
|
+
"--pager",
|
|
65
|
+
action="store_true",
|
|
66
|
+
default=None,
|
|
67
|
+
help="Force output through pager (less -RFX)",
|
|
68
|
+
)
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--no-pager",
|
|
71
|
+
action="store_true",
|
|
72
|
+
help="Disable pager and print directly to terminal",
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"-v",
|
|
76
|
+
"--version",
|
|
77
|
+
action="version",
|
|
78
|
+
version=f"%(prog)s {__version__}",
|
|
79
|
+
)
|
|
80
|
+
return parser.parse_args(args)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def read_content(file_arg: str) -> str:
|
|
84
|
+
if file_arg == "-":
|
|
85
|
+
if sys.stdin.isatty():
|
|
86
|
+
# Nothing piped and stdin is a tty
|
|
87
|
+
return ""
|
|
88
|
+
return sys.stdin.read()
|
|
89
|
+
|
|
90
|
+
path = os.path.expanduser(file_arg)
|
|
91
|
+
if not os.path.exists(path):
|
|
92
|
+
sys.stderr.write(f"Error: file not found: {file_arg}\n")
|
|
93
|
+
sys.exit(1)
|
|
94
|
+
|
|
95
|
+
with open(path, "r", encoding="utf-8", errors="replace") as f:
|
|
96
|
+
return f.read()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
100
|
+
args = parse_args(argv)
|
|
101
|
+
|
|
102
|
+
content = read_content(args.file)
|
|
103
|
+
if not content:
|
|
104
|
+
if args.file == "-":
|
|
105
|
+
sys.stderr.write("mdok: no input provided via stdin or file. Use 'mdok --help' for usage.\n")
|
|
106
|
+
return 1
|
|
107
|
+
return 0
|
|
108
|
+
|
|
109
|
+
# Determine terminal dimensions
|
|
110
|
+
is_tty = sys.stdout.isatty()
|
|
111
|
+
term_width, term_height = shutil.get_terminal_size(fallback=(100, 24))
|
|
112
|
+
|
|
113
|
+
# Canvas layout calculations
|
|
114
|
+
config = CanvasConfig(
|
|
115
|
+
max_width=args.width,
|
|
116
|
+
margin=args.margin,
|
|
117
|
+
center=not args.no_center if is_tty else False,
|
|
118
|
+
)
|
|
119
|
+
doc_width, left_margin = calculate_dimensions(term_width, config)
|
|
120
|
+
|
|
121
|
+
# If piped to another process (not a tty) and user didn't specify width/margin,
|
|
122
|
+
# don't pad with left margin
|
|
123
|
+
if not is_tty and args.margin is None and not args.no_center:
|
|
124
|
+
left_margin = 0
|
|
125
|
+
|
|
126
|
+
# Build document
|
|
127
|
+
markdown_doc = DocMarkdown(
|
|
128
|
+
content,
|
|
129
|
+
code_theme=args.code_theme,
|
|
130
|
+
box_style=args.box,
|
|
131
|
+
show_lines=not args.no_lines,
|
|
132
|
+
doc_width=doc_width,
|
|
133
|
+
left_margin=left_margin,
|
|
134
|
+
term_width=term_width,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
canvas = DocumentCanvas(
|
|
138
|
+
renderable=markdown_doc,
|
|
139
|
+
doc_width=doc_width,
|
|
140
|
+
left_margin=left_margin,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
console = Console(theme=DEFAULT_THEME, width=term_width)
|
|
144
|
+
|
|
145
|
+
# Determine whether to page
|
|
146
|
+
use_pager = False
|
|
147
|
+
if is_tty:
|
|
148
|
+
if args.no_pager:
|
|
149
|
+
use_pager = False
|
|
150
|
+
elif args.pager:
|
|
151
|
+
use_pager = True
|
|
152
|
+
else:
|
|
153
|
+
# Auto-pager heuristic: estimate rendered line count
|
|
154
|
+
# Measure rendered lines
|
|
155
|
+
line_count = sum(1 for _ in console.render_lines(canvas, console.options))
|
|
156
|
+
if line_count > term_height - 2:
|
|
157
|
+
use_pager = True
|
|
158
|
+
|
|
159
|
+
if use_pager:
|
|
160
|
+
with console.pager(styles=True):
|
|
161
|
+
console.print(canvas)
|
|
162
|
+
else:
|
|
163
|
+
console.print(canvas)
|
|
164
|
+
|
|
165
|
+
return 0
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
sys.exit(main())
|