Improving Pygments Code Block Display

by Audrey M. Roy Greenfeld | Sun, Jan 26, 2025

Using Pygments, CSS and Ruff to improve how code blocks are displayed on my daily notebook blog.


from execnb.nbio import read_nb
from fasthtml.common import *
from fasthtml.jupyter import JupyUvi
from fastcore.utils import L
import pygments
from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter

Listing My Notebooks' File Paths

My new favorite way of grabbing all my notebooks:

root = Path() if IN_NOTEBOOK else Path("nbs/")
nb_paths = L(root.glob("*.ipynb")).sorted(reverse=True)
nb_paths

Get Sample Cells to Work With

Here I grab a specific cell of a notebook that looks good to play with.

nb = read_nb(nb_paths[10])
def is_code(c): return c.cell_type=='code'
c = L(nb.cells).filter(is_code)[3]
c

Style the Cell

My FT function for styling cells that I built up to in How I Fixed CSS Scope Leakage in Pygments Syntax Highlighting:

def StyledCode(c, style='monokai'):
    "A notebook cell styled as code, with style name as its css class for scope limiting"
    fm = HtmlFormatter(style=style, cssclass=style)
    h = highlight(c, PythonLexer(), fm)
    sd = fm.get_style_defs(f".{style}")
    return Div(Style(sd), NotStr(h), id=style)
show(StyledCode(c.source))

Pad the Cell

I just want to pad the top and bottom with 10 pixels here.

def StyledCode(c, style='monokai'):
    "A notebook cell styled as code, with style name as its css class for scope limiting"
    fm = HtmlFormatter(style=style, cssclass=f"my-{style}", prestyles="padding:10px 0;")
    h = highlight(c, PythonLexer(), fm)
    sd = fm.get_style_defs(f".my-{style}")
    return Style(sd), NotStr(h)

Pygments lets you add inline styles to <pre>. That's nice.

st, sc = StyledCode(c.source)
Div(sc)
show(StyledCode(c.source))

Success: the code is padded on top and bottom with 10px now.

Limiting Line Length on Mobile Devices

On my phone I counted that 52 characters is the maximum I can read on a line of code, before having to scroll. Let's see if Ruff's textwrap breaks lines in a way that keeps Python code valid.

def wrap_text(text, width=52):
    wrapper = textwrap.TextWrapper(width=width)
    wrapped_text = wrapper.fill(text)
    return wrapped_text
wrapped_text = wrap_text(c.source)
print(wrapped_text)
wrapped_text = wrap_text(c.source, width=43)
print(wrapped_text)

Next Steps

If I continue this approach, the next steps will be:

Or I may just implement the padding and move on. We'll see.