Created
September 24, 2024 11:03
-
-
Save KoStard/e6ae4d3f27e55bdcac0641e00f94b7e5 to your computer and use it in GitHub Desktop.
A demo script, showing how to print markdown text into terminal with syntax highlighting without rendering it with tools like rich. This way it still remains the markdown text which you can copy/paste from terminal, but with nice readable colors.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import mistune | |
from mistune.renderers.markdown import MarkdownRenderer | |
from pygments import highlight | |
from pygments.lexers import get_lexer_by_name, MarkdownLexer | |
from pygments.formatters import Terminal256Formatter | |
def markdown_stream_generator(): | |
text = """ | |
# Main Heading | |
## Sub-heading | |
### Third-level heading | |
#### Fourth-level heading | |
This is a paragraph with **bold text**, *italicized text*, and `inline code`. | |
Here's a [link to Google](https://www.google.com). | |
![Alt text for an image](https://example.com/image.jpg) | |
- Unordered list item 1 | |
- Unordered list item 2 | |
- Nested item 2.1 | |
- Nested item 2.2 | |
- Unordered list item 3 | |
1. Ordered list item 1 | |
2. Ordered list item 2 | |
1. Nested ordered item 2.1 | |
2. `Nested ordered` item 2.2 | |
3. Ordered list item 3 | |
> This is a blockquote. | |
> It can span multiple lines. | |
--- | |
Here's a table: | |
| Column 1 | Column 2 | Column 3 | | |
|----------|----------|----------| | |
| Row 1, Col 1 | Row 1, Col 2 | Row 1, Col 3 | | |
| Row 2, Col 1 | Row 2, Col 2 | Row 2, Col 3 | | |
Here's a code block: | |
```python | |
def hello_world(): | |
print("Hello, world!") | |
hello_world() | |
``` | |
```javascript | |
function factorial(n) { | |
return n <= 1 ? 1 : n * factorial(n - 1); | |
} | |
console.log(factorial(5)); | |
``` | |
```ruby | |
class Person | |
attr_accessor :name, :age | |
def initialize(name, age) | |
@name = name | |
@age = age | |
end | |
end | |
person = Person.new("Alice", 30) | |
puts "#{person.name} is #{person.age} years old." | |
``` | |
```java | |
public class HelloWorld { | |
public static void main(String[] args) { | |
System.out.println("Hello, World!"); | |
} | |
} | |
``` | |
```cpp | |
#include <iostream> | |
using namespace std; | |
int main() { | |
int nums[] = {1, 2, 3, 4, 5}; | |
for (int num : nums) { | |
cout << num << " "; | |
} | |
return 0; | |
} | |
``` | |
```sql | |
SELECT customers.name, orders.order_date | |
FROM customers | |
JOIN orders ON customers.id = orders.customer_id | |
WHERE orders.total > 100; | |
``` | |
```html | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Sample Page</title> | |
</head> | |
<body> | |
<h1>Welcome to my website!</h1> | |
<p>This is a paragraph.</p> | |
</body> | |
</html> | |
``` | |
And here's a task list: | |
- [x] Completed task | |
- [ ] Incomplete task | |
- [ ] Another incomplete task | |
Here's some ~~strikethrough text~~. | |
You can also use inline HTML: <span style="color: red;">This text is red</span> | |
Here's a footnote reference[^1]. | |
[^1]: This is the footnote content. | |
""" | |
for index in range(0, len(text), 3): | |
yield text[index : index + 3] | |
def line_aggregator(generator): | |
buffer = "" | |
for chunk in generator: | |
buffer += chunk | |
while "\n" in buffer: | |
line, buffer = buffer.split("\n", 1) | |
yield line + "\n" | |
if buffer: | |
yield buffer | |
renderer = MarkdownRenderer() | |
state = mistune.BlockState() | |
def render_to_markdown(element): | |
rendered = renderer([element], state) | |
return rendered | |
def get_lexer(element): | |
info = element.get("attrs", {}).get("info", "") | |
if info: | |
return get_lexer_by_name(info) | |
else: | |
return MarkdownLexer() | |
def print_markdown(text, lexer): | |
highlighted = highlight(text, lexer, Terminal256Formatter()) | |
print(highlighted, end="") | |
def process_markdown_stream(): | |
ast = mistune.create_markdown(renderer="ast") | |
buffer = "" | |
old_parsed = [] | |
for line in line_aggregator(markdown_stream_generator()): | |
buffer += line | |
parsed = ast(buffer) | |
if len(parsed) == len(old_parsed): | |
continue | |
old_parsed = parsed | |
buffer = line | |
while len(parsed) > 1: | |
element = parsed.pop(0) | |
print_markdown(render_to_markdown(element), get_lexer(element)) | |
if buffer: | |
parsed = ast(buffer) | |
for element in parsed: | |
print_markdown(render_to_markdown(element), get_lexer(element)) | |
process_markdown_stream() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment