markrender 1.1.0__tar.gz → 1.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 (50) hide show
  1. markrender-1.2.0/CHANGELOG.md +46 -0
  2. {markrender-1.1.0/markrender.egg-info → markrender-1.2.0}/PKG-INFO +196 -98
  3. markrender-1.2.0/README.md +471 -0
  4. {markrender-1.1.0 → markrender-1.2.0}/markrender/_version.py +2 -2
  5. {markrender-1.1.0 → markrender-1.2.0}/markrender/colors.py +27 -1
  6. {markrender-1.1.0 → markrender-1.2.0}/markrender/formatters.py +58 -35
  7. {markrender-1.1.0 → markrender-1.2.0}/markrender/parser.py +16 -0
  8. {markrender-1.1.0 → markrender-1.2.0}/markrender/renderer.py +24 -9
  9. {markrender-1.1.0 → markrender-1.2.0/markrender.egg-info}/PKG-INFO +196 -98
  10. {markrender-1.1.0 → markrender-1.2.0}/markrender.egg-info/SOURCES.txt +3 -0
  11. {markrender-1.1.0 → markrender-1.2.0}/markrender.egg-info/scm_file_list.json +4 -0
  12. markrender-1.2.0/tests/test_changelog.py +150 -0
  13. markrender-1.2.0/tests/test_dim_mode.py +119 -0
  14. {markrender-1.1.0 → markrender-1.2.0}/tests/test_formatters.py +15 -0
  15. {markrender-1.1.0 → markrender-1.2.0}/tests/test_parser.py +18 -0
  16. {markrender-1.1.0 → markrender-1.2.0}/tests/test_regressions.py +2 -1
  17. {markrender-1.1.0 → markrender-1.2.0}/tests/test_renderer.py +59 -0
  18. {markrender-1.1.0 → markrender-1.2.0}/tests/test_versioning.py +29 -0
  19. markrender-1.1.0/README.md +0 -373
  20. {markrender-1.1.0 → markrender-1.2.0}/.gitignore +0 -0
  21. {markrender-1.1.0 → markrender-1.2.0}/LICENSE +0 -0
  22. {markrender-1.1.0 → markrender-1.2.0}/MANIFEST.in +0 -0
  23. {markrender-1.1.0 → markrender-1.2.0}/check_truecolor.py +0 -0
  24. {markrender-1.1.0 → markrender-1.2.0}/examples/basic_usage.py +0 -0
  25. {markrender-1.1.0 → markrender-1.2.0}/examples/complete_showcase.py +0 -0
  26. {markrender-1.1.0 → markrender-1.2.0}/examples/definition_lists.py +0 -0
  27. {markrender-1.1.0 → markrender-1.2.0}/examples/footnotes.py +0 -0
  28. {markrender-1.1.0 → markrender-1.2.0}/examples/highlights.py +0 -0
  29. {markrender-1.1.0 → markrender-1.2.0}/examples/link_highlighting.py +0 -0
  30. {markrender-1.1.0 → markrender-1.2.0}/examples/mermaid_diagrams.py +0 -0
  31. {markrender-1.1.0 → markrender-1.2.0}/examples/new_features_demo.py +0 -0
  32. {markrender-1.1.0 → markrender-1.2.0}/examples/progress_bars.py +0 -0
  33. {markrender-1.1.0 → markrender-1.2.0}/examples/streaming_demo.py +0 -0
  34. {markrender-1.1.0 → markrender-1.2.0}/examples/theme_showcase.py +0 -0
  35. {markrender-1.1.0 → markrender-1.2.0}/examples/v1_0_7_showcase.py +0 -0
  36. {markrender-1.1.0 → markrender-1.2.0}/markrender/__init__.py +0 -0
  37. {markrender-1.1.0 → markrender-1.2.0}/markrender/__main__.py +0 -0
  38. {markrender-1.1.0 → markrender-1.2.0}/markrender/cli.py +0 -0
  39. {markrender-1.1.0 → markrender-1.2.0}/markrender/config.py +0 -0
  40. {markrender-1.1.0 → markrender-1.2.0}/markrender/themes.py +0 -0
  41. {markrender-1.1.0 → markrender-1.2.0}/markrender.egg-info/dependency_links.txt +0 -0
  42. {markrender-1.1.0 → markrender-1.2.0}/markrender.egg-info/entry_points.txt +0 -0
  43. {markrender-1.1.0 → markrender-1.2.0}/markrender.egg-info/requires.txt +0 -0
  44. {markrender-1.1.0 → markrender-1.2.0}/markrender.egg-info/top_level.txt +0 -0
  45. {markrender-1.1.0 → markrender-1.2.0}/pyproject.toml +0 -0
  46. {markrender-1.1.0 → markrender-1.2.0}/requirements.txt +0 -0
  47. {markrender-1.1.0 → markrender-1.2.0}/setup.cfg +0 -0
  48. {markrender-1.1.0 → markrender-1.2.0}/setup.py +0 -0
  49. {markrender-1.1.0 → markrender-1.2.0}/test.md +0 -0
  50. {markrender-1.1.0 → markrender-1.2.0}/tests/test_colors.py +0 -0
@@ -0,0 +1,46 @@
1
+ # Changelog
2
+
3
+ All notable changes to MarkRender are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and the project uses [Semantic Versioning](https://semver.org/). Releases are
7
+ cut from conventional commits, and new entries are added by the publish
8
+ workflow when a release goes out.
9
+
10
+ ## [1.1.1] - 2026-10-30
11
+
12
+ ### Fixed
13
+
14
+ - Dim mode now renders the whole response in one uniform muted gray, including paragraphs, lists, tables, quotes, and code blocks.
15
+
16
+ ### Documentation
17
+
18
+ - Clarified the CLI and Python usage examples.
19
+
20
+ ## [1.1.0] - 2026-10-30
21
+
22
+ ### Added
23
+
24
+ - Dim mode for streaming responses, enabled per render call.
25
+ - Theme previews in the README and a `preview-themes` command.
26
+ - `--width`, `--force-color`, and `--version` CLI flags.
27
+ - TOML config file support with warnings for unknown keys.
28
+ - Dynamic code block line-number widths.
29
+ - Better handling of split stream chunks and buffer boundaries.
30
+
31
+ ### Changed
32
+
33
+ - Rewrote the README around CLI and Python usage instead of feature marketing.
34
+ - Dim mode moved from the constructor to a `render()` argument.
35
+ - Themes are now deep-copied so rendering cannot mutate shared theme state.
36
+ - Improved the parser regexes for bold + italic, inline code, links, and blockquotes.
37
+
38
+ ### Fixed
39
+
40
+ - Blockquotes falling through to other block handlers.
41
+ - Dictionary themes loaded from TOML files failing to render.
42
+ - Table overflow when content is wider than the terminal.
43
+ - Encoding fallback when the output stream is not UTF-8.
44
+ - Config files now warn about unknown keys instead of failing silently.
45
+
46
+ Releases before 1.1.0 were published before this changelog existed.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markrender
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Professional terminal markdown renderer for streaming LLM responses
5
5
  Author: Praneeth Gandodi
6
6
  License: MIT
@@ -34,14 +34,14 @@ Dynamic: license-file
34
34
 
35
35
  **Professional Terminal Markdown Renderer for Streaming LLM Responses**
36
36
 
37
- MarkRender is a Python library that renders markdown in terminals, designed for streaming LLM responses. It provides syntax highlighting, multiple color themes, and supports markdown features without flickering.
37
+ MarkRender renders markdown in the terminal. It is built for streaming output, so you can hand it a complete string or feed it chunks from an LLM as they arrive. Syntax highlighting, themes, tables, and the rest work the same either way, without reprinting content that is already on screen.
38
38
 
39
39
  ## Features
40
40
 
41
41
  - **Streaming Support** - Designed for chunk-by-chunk LLM response rendering
42
42
  - **7 Themes** - github-dark, monokai, dracula, nord, one-dark, solarized-dark, solarized-light
43
43
  - **Syntax Highlighting** - Powered by Pygments with 500+ languages
44
- - **Dim Mode** - Render content in dimmed/reduced colors for "thinking" sections
44
+ - **Dim Mode** - Render "thinking" content in a single muted gray
45
45
  - **Theme Preview** - Preview all themes with sample content via CLI
46
46
  - **Line Numbers** - Optional line numbers in code blocks
47
47
  - **Tables** - Table rendering with borders and overflow truncation
@@ -55,183 +55,269 @@ MarkRender is a Python library that renders markdown in terminals, designed for
55
55
 
56
56
  ## Installation
57
57
 
58
+ MarkRender is on PyPI:
59
+
60
+ ```bash
61
+ pip install markrender
62
+ ```
63
+
64
+ That installs the library and the `markrender` command. Check that it worked:
65
+
66
+ ```bash
67
+ markrender --version
68
+ ```
69
+
70
+ Upgrade an existing install with:
71
+
58
72
  ```bash
59
- pip install git+https://github.com/Praneeth-Gandodi/markrender.git
73
+ pip install --upgrade markrender
60
74
  ```
61
75
 
62
- Or install from source:
76
+ If you want to work on MarkRender itself, clone the repo and install it in editable mode instead:
63
77
 
64
78
  ```bash
65
79
  git clone https://github.com/Praneeth-Gandodi/markrender.git
66
80
  cd markrender
67
- pip install -e .
81
+ pip install -e ".[dev]"
82
+ ```
83
+
84
+ ## Command Line
85
+
86
+ Render a file:
87
+
88
+ ```bash
89
+ markrender README.md
90
+ ```
91
+
92
+ Read markdown from stdin:
93
+
94
+ ```bash
95
+ cat notes.md | markrender
96
+ ```
97
+
98
+ On PowerShell:
99
+
100
+ ```powershell
101
+ Get-Content notes.md -Raw | markrender
102
+ ```
103
+
104
+ Pick a theme:
105
+
106
+ ```bash
107
+ markrender --theme dracula notes.md
108
+ ```
109
+
110
+ Adjust code blocks:
111
+
112
+ ```bash
113
+ markrender --no-line-numbers notes.md
114
+ markrender --code-background notes.md
115
+ markrender --no-stream-code notes.md
116
+ ```
117
+
118
+ Set a fixed width when the terminal reports the wrong size, or when the output goes somewhere else:
119
+
120
+ ```bash
121
+ markrender --width 80 notes.md
122
+ ```
123
+
124
+ Force color when piping into another program, a log file, or CI:
125
+
126
+ ```bash
127
+ markrender --force-color notes.md | less -R
128
+ ```
129
+
130
+ List the theme names:
131
+
132
+ ```bash
133
+ markrender --list-themes
68
134
  ```
69
135
 
70
- ## Quick Start
136
+ Preview every theme with sample content:
137
+
138
+ ```bash
139
+ markrender --preview-themes
140
+ ```
141
+
142
+ Running `markrender` with no file and nothing piped in prints an error and exits.
143
+
144
+ ### Options
145
+
146
+ | Option | Description |
147
+ |--------|-------------|
148
+ | `--theme NAME` | Color theme (default: `github-dark`) |
149
+ | `--no-line-numbers` | Hide line numbers in code blocks |
150
+ | `--code-background` | Show a background behind code blocks |
151
+ | `--width N` | Wrap at a fixed width instead of the terminal width |
152
+ | `--no-stream-code` | Render code blocks in one pass instead of line by line |
153
+ | `--force-color` | Emit colors even when the output is not a terminal |
154
+ | `--list-themes` | Print available themes and exit |
155
+ | `--preview-themes` | Render sample markdown in every theme and exit |
156
+ | `-v`, `--version` | Print the version and exit |
157
+
158
+ CLI flags override values from a config file. See [Configuration](#configuration).
159
+
160
+ ## Python API
161
+
162
+ ### Render a string
71
163
 
72
164
  ````python
73
165
  from markrender import MarkdownRenderer
74
166
 
75
- # Create renderer with default theme
76
167
  renderer = MarkdownRenderer()
77
168
 
78
- # Render markdown content
79
- markdown_text = """
80
- # Hello World
169
+ markdown = """
170
+ # Hello
81
171
 
82
- This is **bold** and this is *italic*.
172
+ Some **bold** text, some *italic* text, and `inline code`.
83
173
 
84
174
  ```python
85
175
  def hello():
86
176
  print("Hello from MarkRender!")
87
177
  ```
88
178
 
89
- ## Features
90
- - Item 1
91
- - Item 2
92
- - [x] Completed task
93
- - [ ] Pending task
179
+ - A list item
180
+ - [x] A finished task
181
+ - [ ] A pending task
94
182
  """
95
183
 
96
- renderer.render(markdown_text)
184
+ renderer.render(markdown)
97
185
  renderer.finalize()
98
186
  ````
99
187
 
100
- ### Streaming LLM Responses
188
+ `render()` writes output as it parses, and `finalize()` flushes whatever is still buffered. For a string you already have, call them one after the other.
101
189
 
102
- Perfect for rendering streaming responses from LLM APIs:
190
+ ### Streaming LLM responses
103
191
 
104
192
  ```python
105
193
  from markrender import MarkdownRenderer
106
194
  from openai import OpenAI
107
195
 
108
196
  client = OpenAI()
109
- renderer = MarkdownRenderer(theme='github-dark')
197
+ renderer = MarkdownRenderer(theme="github-dark")
110
198
 
111
199
  stream = client.chat.completions.create(
112
- model="gpt-4",
200
+ model="gpt-4o",
113
201
  messages=[{"role": "user", "content": "Explain quantum computing"}],
114
- stream=True
202
+ stream=True,
115
203
  )
116
204
 
117
205
  for chunk in stream:
118
- content = chunk.choices[0].delta.content
119
- if content:
120
- renderer.render(content)
206
+ text = chunk.choices[0].delta.content
207
+ if text:
208
+ renderer.render(text)
121
209
 
122
210
  renderer.finalize()
123
211
  ```
124
212
 
125
- ### Dim Mode
126
-
127
- Use dim mode for "thinking" sections or less prominent content:
128
-
129
- ```python
130
- from markrender import MarkdownRenderer
213
+ The renderer keeps partial lines and open blocks in an internal buffer, so chunks can split anywhere: mid-word, mid-table, or in the middle of a code fence. Feed every chunk and call `finalize()` once when the stream ends.
131
214
 
132
- renderer = MarkdownRenderer()
215
+ ### Dim mode
133
216
 
134
- # Normal rendering
135
- renderer.render("This is **normal** content")
217
+ `render()` takes a `dim_mode` argument, which draws that chunk as plain muted gray. Formatting colors, bold, and syntax highlighting are dropped so the whole block reads like thinking text instead of competing with the answer:
136
218
 
137
- # Dim/reduced color rendering
138
- renderer.render("This content is dimmed and less prominent", dim_mode=True)
219
+ ```python
220
+ renderer.render("Let me think about this...", dim_mode=True)
221
+ renderer.render("Here is the answer.", dim_mode=False)
139
222
  ```
140
223
 
141
- ### Theme Preview
142
-
143
- Preview all available themes from the CLI:
144
-
145
- ```bash
146
- markrender --preview-themes
147
- ```
224
+ Dim mode applies per call, so you can turn it on and off while streaming.
148
225
 
149
- ## Themes
226
+ ### Custom output
150
227
 
151
- MarkRender includes 7 professional color themes:
228
+ By default output goes to stdout. Pass any text stream with `output`:
152
229
 
153
230
  ```python
154
- themes = [
155
- 'github-dark', # GitHub's dark theme (default)
156
- 'monokai', # Popular Monokai theme
157
- 'dracula', # Dracula theme
158
- 'nord', # Nord color palette
159
- 'one-dark', # Atom One Dark
160
- 'solarized-dark', # Solarized Dark
161
- 'solarized-light' # Solarized Light
162
- ]
231
+ from markrender import MarkdownRenderer
163
232
 
164
- renderer = MarkdownRenderer(theme='dracula')
233
+ with open("rendered.txt", "w", encoding="utf-8") as log:
234
+ renderer = MarkdownRenderer(output=log, force_color=True)
235
+ renderer.render("# Saved to a file\n")
236
+ renderer.finalize()
165
237
  ```
166
238
 
167
- List available themes:
239
+ Color detection still looks at stdout, so set `force_color=True` if you want ANSI colors in the file.
168
240
 
169
- ```bash
170
- markrender --list-themes
171
- ```
241
+ ### Constructor options
172
242
 
173
- ## Configuration
243
+ | Parameter | Default | Description |
244
+ |-----------|---------|-------------|
245
+ | `theme` | `"github-dark"` | Theme name |
246
+ | `code_background` | `False` | Draw a background behind code blocks |
247
+ | `line_numbers` | `True` | Show line numbers in code blocks |
248
+ | `inline_code_color` | theme default | ANSI color code for inline code |
249
+ | `width` | auto-detect | Wrap width in characters |
250
+ | `force_color` | `False` | Emit color even when the output is not a TTY |
251
+ | `stream_code` | `True` | Render code lines as they arrive |
252
+ | `output` | `sys.stdout` | Stream to write to |
253
+ | `use_config` | `True` | Load a config file if one is found |
254
+ | `config` | `None` | Pass a `RendererConfig` directly |
174
255
 
175
- ### Python API
256
+ Custom inline code color uses the `rgb` helper:
176
257
 
177
258
  ```python
178
259
  from markrender import MarkdownRenderer
179
260
  from markrender.colors import rgb
180
261
 
181
262
  renderer = MarkdownRenderer(
182
- theme='monokai', # Color theme
183
- code_background=False, # Show background in code blocks
184
- line_numbers=True, # Show line numbers in code
185
- inline_code_color=rgb(255, 100, 200), # Custom inline code color
186
- width=100, # Terminal width (auto-detect by default)
187
- force_color=False, # Force color output
188
- stream_code=True # Stream code lines as they arrive
263
+ theme="monokai",
264
+ inline_code_color=rgb(255, 100, 200),
265
+ width=100,
189
266
  )
190
267
  ```
191
268
 
192
- ### Parameters
193
-
194
- - **theme** (str): Color theme name (default: `'github-dark'`)
195
- - **code_background** (bool): Show background in code blocks (default: `False`)
196
- - **line_numbers** (bool): Show line numbers in code blocks (default: `True`)
197
- - **inline_code_color** (str): Custom ANSI color code for inline code (default: theme default)
198
- - **width** (int): Terminal width in characters (default: auto-detect)
199
- - **force_color** (bool): Force color output even if terminal does not support it (default: `False`)
200
- - **stream_code** (bool): Render code lines as they arrive instead of buffering (default: `True`)
201
- - **output** (file): Output stream (default: `sys.stdout`)
202
-
203
- ### CLI Usage
269
+ ## Configuration
204
270
 
205
- ```bash
206
- markrender README.md
207
- markrender --theme dracula file.md
208
- cat file.md | markrender
209
- markrender --preview-themes
210
- markrender --list-themes
211
- markrender --no-line-numbers --code-background file.md
212
- markrender --width 80 --force-color file.md
213
- ```
271
+ MarkRender reads a TOML config file if one exists. It checks these locations in order and uses the first match:
214
272
 
215
- ### Config File
273
+ 1. `.markrender.toml` in the current directory
274
+ 2. `~/.markrender/config.toml`
275
+ 3. `~/.config/markrender/config.toml`
216
276
 
217
- MarkRender supports TOML configuration files. Place a `.markrender.toml` in your current directory or `~/.markrender/config.toml`:
277
+ Example `.markrender.toml`:
218
278
 
219
279
  ```toml
220
280
  [theme]
221
- name = "github-dark"
281
+ name = "dracula"
222
282
 
223
283
  [rendering]
224
- code_background = false
225
- line_numbers = true
284
+ code_background = true
285
+ line_numbers = false
226
286
 
227
287
  [output]
228
- # width = 80
288
+ width = 100
229
289
  force_color = false
230
290
 
231
291
  [features]
232
- stream_code = true
292
+ stream_code = false
233
293
  ```
234
294
 
295
+ Values are applied in this order, from highest to lowest priority:
296
+
297
+ 1. Arguments passed to `MarkdownRenderer(...)`
298
+ 2. The config file
299
+ 3. Built-in defaults
300
+
301
+ Only non-`None` arguments override the config, so `MarkdownRenderer()` picks up your file settings. Pass `use_config=False` to ignore config files entirely.
302
+
303
+ ## Themes
304
+
305
+ | Theme | Notes |
306
+ |-------|-------|
307
+ | `github-dark` | GitHub's dark theme (default) |
308
+ | `monokai` | Classic Monokai palette |
309
+ | `dracula` | Dracula palette |
310
+ | `nord` | Nord palette |
311
+ | `one-dark` | Atom One Dark |
312
+ | `solarized-dark` | Solarized Dark |
313
+ | `solarized-light` | Solarized Light |
314
+
315
+ ```python
316
+ renderer = MarkdownRenderer(theme="dracula")
317
+ ```
318
+
319
+ See the names from the CLI with `markrender --list-themes`, or render a sample in each theme with `markrender --preview-themes`.
320
+
235
321
  ## Supported Markdown Features
236
322
 
237
323
  ### Headings
@@ -336,6 +422,11 @@ Hello :wave: Let's :rocket: go!
336
422
  - **Note-Taking Apps** - Terminal-based markdown note viewers
337
423
  - **Log Viewers** - Render structured logs with markdown
338
424
 
425
+ ## Changelog
426
+
427
+ Release notes come from conventional commit messages, so the history stays in
428
+ one place. See [CHANGELOG.md](CHANGELOG.md) for what changed in each version.
429
+
339
430
  ## Development
340
431
 
341
432
  ### Setup Development Environment
@@ -372,12 +463,19 @@ no version number to edit by hand.
372
463
  2. Choose `auto` (recommended) or an explicit `patch`, `minor`, or `major` bump.
373
464
  3. The workflow runs the tests, creates the next `vX.Y.Z` tag, builds the
374
465
  sdist and wheel, publishes to PyPI, and creates a GitHub release.
466
+ 4. Release notes are generated from the commits since the last tag, and the
467
+ same entry is added to [CHANGELOG.md](CHANGELOG.md) on `main`.
375
468
 
376
469
  With `auto`, commit messages since the last tag decide the bump:
377
470
 
378
471
  - `feat!:` or a `BREAKING CHANGE:` footer → major
379
472
  - `feat:` → minor
380
- - everything else → patch
473
+ - `fix:`, `perf:`, `refactor:`, or `revert:` → patch
474
+ - `docs:`, `test:`, `chore:`, `ci:`, `build:`, and `style:` don't trigger a
475
+ release on their own
476
+
477
+ Write commit subjects in the `type(scope): summary` form so the changelog and
478
+ version bump stay accurate.
381
479
 
382
480
  Publishing uses PyPI Trusted Publishing (OIDC), so no API token is stored in
383
481
  the repository. Configure it once: