``, the arrow pseudo-element gets cut off vertically wherever the parent line number element naturally
ends. Since both the line and the line number element share a grid row, the line number element always matches the
height of the soft-wrapped line.
Responsive Split/Unified Layout Selection
.........................................
To dynamically change between unified and side-by-side views, wsdiff uses a web-standard `Media Query`_. By default, the
page is laid out for side-by-side view. In the HTML source, the diff is listed as it is displayed in side-by-side view,
with the old and new lines along with their line numbers interleaved.
The magic happens when the media query gets triggered by a narrow screen width. The media query re-adjusts the layout in
four core steps:
1. All unchanged lines in the left (old) column are hidden.
2. The left content column of the grid layout is hidden, so that now there are three columns: old line number, new line
number, and unified content.
3. All deleted or changed lines from the left (old) column are re-located to the right column. They naturally slot in
in the right spot because they already appear in the right order in the HTML source.
4. By slotting in the old lines in the right column, we have created gaps in the line number columns. Every deleted
line has an empty cell in the new line number column, and every inserted line has one in the old line number column.
The CSS adjusts the layout of these empty cells such that the border lines align nicely, and it overrides the
newline markers so that they only show in the right (new) line number column, not both.
Since this is all CSS, it happens automatically and near-instantly. Since it is using only web standard features, it
works across browsers and platforms.
Unchanged Line Folding in CSS
.............................
When showing the diff of a large file, it is usually best to hide large runs of unchanged lines. wsdiff does this
similar to code folding in text editors. When a long run of unchanged lines is detected, a marker is placed spanning the
diff. This marker contains a checkbox that can be toggled to hide the unchanged lines. This feature is done completely
in CSS using a ``:has(input[type="checkbox"]:checked)`` selector.
The actual mechanics are quite simple. To cleanly hide the lines, they must be placed in a container ````. That div
has a CSS subgrid layout using ``display: grid; grid-template-columns: subgrid;``, meaning that its contents align to
the surrounding diff grid.
Dark Mode
.........
Integrating a website with the OS-level dark mode is surprisingly easy. All you need is a `Media Query`_ that selects
for ``@media (prefers-color-scheme: dark)`` and you're good. wsdiff uses named colors using `CSS Custom Properties`_, so
the actual dark mode media query only needs to override these color properties, and the rest of the CSS will be
re-computed automatically.
Limitations: Text selection
...........................
A limitation in having a combined, single HTML source for both side-by-side and unified diffs is that text selection
only works naturally in either mode. You can't make text selection work in both simultaneously without re-sorting the
lines in the HTML source, since there is no way to override the text selection order from pure CSS. In wsdiff, I worked
around this issue by just disabling text selection on the unchanged lines in the left (old) column, so selecting text in
the right column copies the unified diff as one would expect.
Try it yourself!
----------------
You can find the demo from above at `this link `__.
You can install wsdiff yourself `from PyPI `__:
.. code:: sh
$ pip install -U wsdiff
Successfully installed wsdiff-0.3.1
$ wsdiff old.py new.py -o diff.html
.. _`CSS grid layout`: https://css-tricks.com/snippets/css/complete-guide-grid/
.. _`Media Query`: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries
.. _`CSS Custom Properties`: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties