@@ -153,6 +153,8 @@ def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult
153
153
)
154
154
else :
155
155
# Styled text for h2 and beyond
156
+ if self .level :
157
+ yield Text ("\n " )
156
158
yield text
157
159
158
160
@@ -173,8 +175,10 @@ def __init__(self, lexer_name: str, theme: str) -> None:
173
175
174
176
def __console__ (self , console : Console , options : ConsoleOptions ) -> RenderResult :
175
177
code = str (self .text ).rstrip ()
176
- syntax = Syntax (code , self .lexer_name , theme = self .theme )
177
- yield Panel (syntax , style = "dim" )
178
+ syntax = Panel (
179
+ Syntax (code , self .lexer_name , theme = self .theme ), style = "dim" , box = box .SQUARE
180
+ )
181
+ yield syntax
178
182
179
183
180
184
class BlockQuote (TextElement ):
@@ -289,7 +293,7 @@ def render_number(
289
293
yield new_line
290
294
291
295
292
- class ImageItem (MarkdownElement ):
296
+ class ImageItem (TextElement ):
293
297
"""Renders a placeholder for an image."""
294
298
295
299
new_line = False
@@ -305,17 +309,26 @@ def create(cls, markdown: "Markdown", node: Any) -> "MarkdownElement":
305
309
Returns:
306
310
MarkdownElement: A new markdown element
307
311
"""
308
- return cls (node .title , node . destination )
312
+ return cls (node .destination , markdown . hyperlinks )
309
313
310
- def __init__ (self , title : Optional [str ], destination : str ) -> None :
311
- self .title = title
314
+ def __init__ (self , destination : str , hyperlinks : bool ) -> None :
312
315
self .destination = destination
316
+ self .hyperlinks = hyperlinks
317
+ self .link : Optional [str ] = None
313
318
super ().__init__ ()
314
319
320
+ def on_enter (self , context : "MarkdownContext" ) -> None :
321
+ self .link = context .current_style .link
322
+ self .text = Text (justify = "left" )
323
+ super ().on_enter (context )
324
+
315
325
def __console__ (self , console : Console , options : ConsoleOptions ) -> RenderResult :
316
- yield Text .assemble (
317
- (self .title or "🌆" , "italic" ), " " , f"({ self .destination } ) " , end = ""
318
- )
326
+ link_style = Style (link = self .link or self .destination or None )
327
+ title = self .text or Text (self .destination .strip ("/" ).rsplit ("/" , 1 )[- 1 ])
328
+
329
+ if self .hyperlinks :
330
+ title .stylize_all (link_style )
331
+ yield Text .assemble ("🌆 " , title , " " , end = "" )
319
332
320
333
321
334
class MarkdownContext :
@@ -356,6 +369,7 @@ class Markdown:
356
369
code_theme (str, optional): Pygments theme for code blocks. Defaults to "monokai".
357
370
justify (JustifyValues, optional): Justify value for paragraphs. Defaults to None.
358
371
style (Union[str, Style], optional): Optional style to apply to markdown.
372
+ hyperlinks (bool, optional): Enable hyperlinks. Defaults to ``True``.
359
373
"""
360
374
361
375
elements : ClassVar [Dict [str , Type [MarkdownElement ]]] = {
@@ -368,21 +382,23 @@ class Markdown:
368
382
"item" : ListItem ,
369
383
"image" : ImageItem ,
370
384
}
371
- inlines = {"emph" , "strong" , "code" , "link" , " strike" }
385
+ inlines = {"emph" , "strong" , "code" , "strike" }
372
386
373
387
def __init__ (
374
388
self ,
375
389
markup : str ,
376
390
code_theme : str = "monokai" ,
377
391
justify : JustifyValues = None ,
378
392
style : Union [str , Style ] = "none" ,
393
+ hyperlinks : bool = True ,
379
394
) -> None :
380
395
self .markup = markup
381
396
parser = Parser ()
382
397
self .parsed = parser .parse (markup )
383
398
self .code_theme = code_theme
384
399
self .justify = justify
385
400
self .style = style
401
+ self .hyperlinks = hyperlinks
386
402
387
403
def __console__ (self , console : Console , options : ConsoleOptions ) -> RenderResult :
388
404
"""Render markdown to the console."""
@@ -392,7 +408,6 @@ def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult
392
408
inlines = self .inlines
393
409
new_line = False
394
410
for current , entering in nodes :
395
- # print(current, current.literal)
396
411
node_type = current .t
397
412
if node_type in ("html_inline" , "html_block" , "text" ):
398
413
context .on_text (current .literal .replace ("\n " , " " ))
@@ -402,6 +417,23 @@ def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult
402
417
elif node_type == "softbreak" :
403
418
if entering :
404
419
context .on_text (" " )
420
+ elif node_type == "link" :
421
+ if entering :
422
+ link_style = console .get_style ("markdown.link" )
423
+ if self .hyperlinks :
424
+ link_style .link = current .destination
425
+ context .enter_style (link_style )
426
+ else :
427
+ context .leave_style ()
428
+ if not self .hyperlinks :
429
+ context .on_text (" (" )
430
+ style = Style (underline = True ) + console .get_style (
431
+ "markdown.link_url"
432
+ )
433
+ context .enter_style (style )
434
+ context .on_text (current .destination )
435
+ context .leave_style ()
436
+ context .on_text (")" )
405
437
elif node_type in inlines :
406
438
if current .is_container ():
407
439
if entering :
@@ -413,12 +445,6 @@ def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult
413
445
if current .literal :
414
446
context .on_text (current .literal )
415
447
context .leave_style ()
416
- if current .destination and not entering :
417
- context .on_text (" (" )
418
- context .enter_style ("markdown.link_url" )
419
- context .on_text (current .destination )
420
- context .leave_style ()
421
- context .on_text (") " )
422
448
else :
423
449
element_class = self .elements .get (node_type ) or UnknownElement
424
450
if current .is_container ():
@@ -470,6 +496,20 @@ def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult
470
496
action = "store_true" ,
471
497
help = "force color for non-terminals" ,
472
498
)
499
+ parser .add_argument (
500
+ "-t" ,
501
+ "--code-theme" ,
502
+ dest = "code_theme" ,
503
+ default = "monokai" ,
504
+ help = "pygments code theme" ,
505
+ )
506
+ parser .add_argument (
507
+ "-y" ,
508
+ "--hyperlinks" ,
509
+ dest = "hyperlinks" ,
510
+ action = "store_true" ,
511
+ help = "enable hyperlinks" ,
512
+ )
473
513
parser .add_argument (
474
514
"-w" ,
475
515
"--width" ,
@@ -478,11 +518,23 @@ def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult
478
518
default = None ,
479
519
help = "width of output (default will auto-detect)" ,
480
520
)
521
+ parser .add_argument (
522
+ "-j" ,
523
+ "--justify" ,
524
+ dest = "justify" ,
525
+ action = "store_true" ,
526
+ help = "enable full text justify" ,
527
+ )
481
528
args = parser .parse_args ()
482
529
483
530
from rich .console import Console
484
531
485
532
console = Console (force_terminal = args .force_color , width = args .width )
486
533
with open (args .path , "rt" ) as markdown_file :
487
- markdown = Markdown (markdown_file .read ())
534
+ markdown = Markdown (
535
+ markdown_file .read (),
536
+ justify = "full" if args .justify else "left" ,
537
+ code_theme = args .code_theme ,
538
+ hyperlinks = args .hyperlinks ,
539
+ )
488
540
console .print (markdown )
0 commit comments