How the nGPT Markdown Rendering System Handles Elements and Styling Customizations
The nGPT markdown rendering system leverages the Rich library to stream live Markdown in a bordered panel, automatically truncating content to fit terminal dimensions while centralizing color styling through a dedicated configuration dictionary.
The nazdridoy/ngpt repository implements a sophisticated markdown rendering system that transforms AI responses into beautifully formatted terminal output. This system combines the rich library's capabilities with custom truncation logic and centralized color management to deliver a seamless streaming experience.
Architecture of the Markdown Rendering Pipeline
The markdown rendering system in ngpt/ui/renderers.py processes AI responses through a six-stage pipeline that balances performance with visual polish.
Creating the Rich Console
The pipeline begins by instantiating a Console() object from the rich library. This console serves as the low-level rendering target and automatically handles ANSI-color support detection across different terminal environments.
Wrapping Content in a Panel
The system wraps the Markdown content inside a Panel with a rounded box style. The implementation uses Panel(Markdown(""), title=panel_title, box=rich.box.ROUNDED, border_style="cyan") to create a distinct visual container with a cyan border and customizable header.
Initializing the Live Display
To prevent flickering during streaming, the code starts a Live display with Live(md_obj, console=console, refresh_per_second=10, auto_refresh=False). This maintains the panel on-screen while its contents update in-place at a controlled refresh rate.
Handling Streaming Chunks
The update_content() function inside renderers.py processes each incoming chunk by replacing the panel's renderable with a fresh Markdown object. The system also implements intelligent truncation: it calculates display_height using shutil.get_terminal_size() and slices the markdown text when it exceeds terminal capacity, showing only the most recent lines based on a max(10, min(30, ...)) formula.
Synchronizing with the Spinner
While the LLM generates output, a background spinner runs via setup_spinner() in renderers.py and ngpt/ui/tui.py. The create_spinner_handling_callback() function ensures the first piece of content automatically stops the spinner, clears its line, and hands control to the live panel.
Applying Color Styling
All color codes are centralized in ngpt/ui/colors.py within the COLORS dictionary. The rendering code references COLORS['cyan'], COLORS['reset'], and other keys, ensuring that modifying a single value in this dictionary propagates to the markdown header, spinner text, and border styles.
Element-Level Handling in the Markdown Rendering System
The markdown rendering system delegates specific element parsing to rich.markdown.Markdown, which translates syntax into Rich Text objects that inherit the console's color configuration.
Structural Elements
Headers, lists, code blocks, tables, and block-quotes are parsed natively by the Rich library. The nGPT system does not intercept these elements, allowing the underlying library to handle the complex AST translation while the panel container manages the visual presentation.
Inline Formatting
Bold, italic, and hyperlink styling are supported out-of-the-box by Rich. While nGPT does not add extra processing layers for inline elements, you can influence the visual result by tweaking the console theme or the COLORS dictionary in colors.py.
Custom Panel Title
The panel header displaying "🤖 nGPT" is created with Text(..., style="cyan bold"), giving it a distinct appearance separate from the content. This styling can be modified by editing the panel_title variable within the prettify_streaming_markdown() function in renderers.py.
Dynamic Styling Customizations
The markdown rendering system offers several extension points for customizing the visual experience without modifying core streaming logic.
Panel Appearance
You can modify the border shape, color, and spacing by adjusting the Panel constructor parameters in prettify_streaming_markdown(). Changing box=rich.box.ROUNDED to alternatives like rich.box.DOUBLE or modifying border_style="cyan" to another color key alters the container aesthetics.
Terminal-Size-Aware Truncation
The system adapts to viewport constraints by calculating display height via shutil.get_terminal_size(). You can customize the truncation limits by editing the formula max(10, min(30, int(term_height * 0.7))) in renderers.py, adjusting the minimum (10), maximum (30), or percentage multiplier (0.7) to control how much content remains visible.
Color Palette Management
All UI colors are centralized in the COLORS dictionary within ngpt/ui/colors.py. Editing values such as "cyan": "\033[96m" instantly propagates changes to the panel border, header text, and spinner animations across all CLI modes.
Spinner Styling
The spinner text color is passed via color=COLORS['cyan'] in the setup_spinner() function. Modifying the referenced color key changes the spinner appearance independently of the markdown panel rendering logic.
Integration with CLI Modes
Every interactive mode in nGPT—including chat, text, code, and rewrite—imports the prettify_streaming_markdown function from ngpt/ui/renderers.py to provide consistent visual output.
Markdown Mode Operation
When the user does not pass the --plaintext flag, the CLI mode invokes:
live_display, stream_callback, setup_spinner = prettify_streaming_markdown()
This returns a tuple containing the live display object, a callback function for streaming chunks, and a spinner setup function. The mode then starts the spinner using setup_spinner(), which runs while the LLM generates output. As chunks arrive, they are fed to stream_callback, triggering live Markdown updates within the bordered panel.
Plaintext Fallback
If the user specifies --plaintext, the spinner logic switches to setup_plaintext_spinner, and responses print as raw text without Rich formatting. This bypasses the prettify_streaming_markdown pipeline entirely, providing unstyled output for environments where ANSI codes are unsupported or undesired.
Code Examples
Setting Up Live Markdown Rendering
The following simplified example demonstrates how to initialize the rendering pipeline programmatically:
from ngpt.ui.renderers import prettify_streaming_markdown
import threading
live, update, start_spinner = prettify_streaming_markdown()
stop_spinner = start_spinner(threading.Event(), "Thinking…")
# Simulated streaming loop
for chunk in streaming_response():
update(chunk) # updates the live panel
stop_spinner() # stops the spinner when done
The update function handles content truncation and panel refreshes automatically, ensuring the display remains responsive even during high-volume streaming.
Changing the Panel Border Color
To customize the visual appearance, modify the color definitions in ngpt/ui/colors.py:
COLORS["cyan"] = "\033[94m" # a deeper blue
Because prettify_streaming_markdown references border_style="cyan" when constructing the Panel, this change immediately affects the border color across all CLI modes.
Customizing Truncation Limits
Adjust the viewport constraints in ngpt/ui/renderers.py to change how much content remains visible:
display_height = max(5, min(40, int(term_height * 0.7))) # new limits
This modification allows the panel to display between 5 and 40 lines of content, adapting dynamically to terminal resizing while maintaining the 70% height ratio.
Key Files in the Markdown Rendering System
The markdown rendering system spans several modules that handle distinct responsibilities:
-
ngpt/ui/renderers.py– Contains the core streaming logic, includingprettify_streaming_markdown(),update_content(), and spinner coordination viasetup_spinner()andcreate_spinner_handling_callback(). -
ngpt/ui/colors.py– Centralizes theCOLORSdictionary that defines ANSI escape sequences for all UI elements, enabling system-wide color changes from a single location. -
ngpt/ui/tui.py– Implements the background spinner animation used while waiting for LLM responses. -
ngpt/cli/modes/*.py(e.g.,chat.py,text.py) – CLI entry points that importprettify_streaming_markdownand handle the--plaintextflag to toggle between styled and raw output. -
ngpt/api/client.py– API wrapper that setsmarkdown_format=Trueto encourage the LLM to return Markdown-formatted responses compatible with the rendering system.
Summary
- The markdown rendering system in
nazdridoy/ngptleverages therichlibrary to stream live Markdown within a bordered, rounded panel that updates in real-time. - Centralized color management via
ngpt/ui/colors.pyallows system-wide styling changes by modifying a single dictionary. - Intelligent truncation in
ngpt/ui/renderers.pyensures content fits within terminal viewports by calculating dynamic height limits based onshutil.get_terminal_size(). - Spinner synchronization provides visual feedback during LLM generation, automatically transitioning to the live panel when content arrives.
- All interactive CLI modes share the same rendering pipeline through the
prettify_streaming_markdown()function, with a--plaintextfallback for unstyled output.
Frequently Asked Questions
How does the markdown rendering system prevent content from overflowing the terminal?
The system calculates available viewport space using shutil.get_terminal_size() in ngpt/ui/renderers.py. It applies a dynamic height formula—typically max(10, min(30, int(term_height * 0.7)))—to determine how many lines to display. When content exceeds this limit, the update_content() function truncates the text to show only the most recent lines, ensuring the panel never scrolls beyond the visible terminal area.
Can I customize the colors used in the markdown rendering system without modifying the source code?
While the color definitions reside in ngpt/ui/colors.py within the COLORS dictionary, you can modify these values before runtime or fork the repository to change them permanently. Each UI component references these centralized color keys—for example, border_style="cyan" in the panel constructor—so changing "cyan" in the dictionary propagates instantly to borders, headers, and spinners across all CLI modes.
What happens to the markdown rendering system when I use the --plaintext flag?
When you invoke nGPT with --plaintext, the application bypasses the Rich-based pipeline entirely. Instead of calling prettify_streaming_markdown(), the CLI modes use setup_plaintext_spinner for loading indicators and print raw text chunks directly to stdout without Panel containers, border styling, or Markdown parsing. This provides unformatted output suitable for piping to other programs or terminals without ANSI support.
How does the markdown rendering system handle code blocks and tables within streaming content?
The system delegates element parsing to rich.markdown.Markdown, which automatically converts standard Markdown syntax—including fenced code blocks, tables, blockquotes, and headers—into Rich Text objects. As the update() function in ngpt/ui/renderers.py receives new chunks, it reconstructs the Markdown object, allowing Rich to re-render the entire document with proper syntax highlighting and table formatting within the live panel boundaries.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →