audrey.feldroy.com

The experimental notebooks of Audrey M. Roy Greenfeld. This website and all its notebooks are open-source at github.com/audreyfeldroy/audrey.feldroy.com


# 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
(#50) [Path('2025-01-26-Improving-Pygments-Code-Block-Display.ipynb'),Path('2025-01-25-This-Site-Is-Now-Powered-by-This-Notebook-Part-2.ipynb'),Path('2025-01-24-Creating-In-Notebook-Images-for-Social-Media-With-PIL-Pillow.ipynb'),Path('2025-01-23-Troubleshooting-MonsterUI-on-This-Site.ipynb'),Path('2025-01-23-This-Site-Is-Now-Powered-by-This-Notebook.ipynb'),Path('2025-01-22-MonsterUI-Buttons-and-Links.ipynb'),Path('2025-01-22-Customizing-FastHTML-Headers-From-Notebook-Contents.ipynb'),Path('2025-01-21-SVG-Animation-in-FastHTML.ipynb'),Path('2025-01-20-Dark-and-Light-Mode-in-FastHTML.ipynb'),Path('2025-01-19-Genanki-and-fastcore.ipynb'),Path('2025-01-18-Alarm-Sounds-App.ipynb'),Path('2025-01-17-Alarm-Clock-Sounds.ipynb'),Path('2025-01-16-Cosine-Similarity-Breakdown-in-LaTeX.ipynb'),Path('2025-01-14-Constructing-SQLite-Tables-for-Notebooks-and-Search.ipynb'),Path('2025-01-13-SQLite-FTS5-Tokenizers-unicode61-and-ascii.ipynb'),Path('2025-01-12-A-Better-Notebook-Index-Page.ipynb'),Path('2025-01-11-NBClassic-Keyboard-Shortcuts-in-Command-and-Dual-Mode.ipynb'),Path('2025-01-10-Understanding-FastHTML-Routes-Requests-and-Redirects.ipynb'),Path('2025-01-09-Reading-and-Writing-Jupyter-Notebooks-With-Python.ipynb'),Path('2025-01-08-HTML-Title-Tag-in-FastHTML.ipynb')...]

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

{ 'cell_type': 'code',

  'execution_count': 16,

  'id': '00540ad9',

  'idx_': 10,

  'metadata': {},

  'outputs': [ { 'data': { 'text/plain': [ "(#3) [['Magandang hapon', 'Good "

                                           "afternoon'],['Magandang gabi', "

                                           "'Good evening'],['Paalam', "

                                           "'Goodbye']]"]},

                 'execution_count': 16,

                 'metadata': {},

                 'output_type': 'execute_result'}],

  'source': "notes = L(['Magandang hapon', 'Good afternoon'],\n"

            "    ['Magandang gabi', 'Good evening'],\n"

            "    ['Paalam', 'Goodbye'])\n"

            'notes'}

{'cell_type': 'code', 'execution_count': 16, 'id': '00540ad9', 'metadata': {}, 'outputs': [{'data': {'text/plain': ["(#3) [['Magandang hapon', 'Good afternoon'],['Magandang gabi', 'Good evening'],['Paalam', 'Goodbye']]"]}, 'execution_count': 16, 'metadata': {}, 'output_type': 'execute_result'}], 'source': "notes = L(['Magandang hapon', 'Good afternoon'],\n ['Magandang gabi', 'Good evening'],\n ['Paalam', 'Goodbye'])\nnotes", 'idx_': 10}

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))
notes = L(['Magandang hapon', 'Good afternoon'],

    ['Magandang gabi', 'Good evening'],

    ['Paalam', 'Goodbye'])

notes

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)

<div><div class="my-monokai"><pre style="padding:10px 0;"><span></span><span class="n">notes</span> <span class="o">=</span> <span class="n">L</span><span class="p">([</span><span class="s1">&#39;Magandang hapon&#39;</span><span class="p">,</span> <span class="s1">&#39;Good afternoon&#39;</span><span class="p">],</span>

    <span class="p">[</span><span class="s1">&#39;Magandang gabi&#39;</span><span class="p">,</span> <span class="s1">&#39;Good evening&#39;</span><span class="p">],</span>

    <span class="p">[</span><span class="s1">&#39;Paalam&#39;</span><span class="p">,</span> <span class="s1">&#39;Goodbye&#39;</span><span class="p">])</span>

<span class="n">notes</span>

</pre></div>

</div>



div(('
notes = L(['Magandang hapon', 'Good afternoon'],\n    ['Magandang gabi', 'Good evening'],\n    ['Paalam', 'Goodbye'])\nnotes\n
\n',),{})
show(StyledCode(c.source))
notes = L(['Magandang hapon', 'Good afternoon'],

    ['Magandang gabi', 'Good evening'],

    ['Paalam', 'Goodbye'])

notes

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.

© 2024-2025 Audrey M. Roy Greenfeld