Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*.xlsx binary
*.pptx binary
*.pdf binary
*.fgb binary
*.dll binary
*.so binary
*.dylib binary
Expand Down
13 changes: 9 additions & 4 deletions claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ apart.
three fit from `ImagePane.Width/Height` — the file header's numbers, not the decoder's — one blank
line under the pane's rows, so the placement rule lives once. Headers are sniffed by hand
(`ImageHeader`) rather than by System.Drawing, which does not exist on macOS or Linux.
- Documents (PDF, docx, xlsx, pptx, and SVG drawn beside its text) need **`src/DiffEngineViewer.Documents`**,
a separate assembly with Morph, Morph.PDFium, Skia and the OpenXml SDK behind it: tens of MB per
- Documents (PDF, docx, xlsx, pptx, and SVG and maps drawn beside their text) need **`src/DiffEngineViewer.Documents`**,
a separate assembly with Morph, Morph.PDFium, Skia, GeoConvert and the OpenXml SDK behind it: tens of MB per
RID. So it ships only in a `documents/` folder of the three tool packages and of the tray (one folder
at `viewer/documents/`, which each RID copy finds one directory up), never in DiffEngine's bundle.
`Documents.targets` adds it, and only to RID-less builds - the bundle is the only per-RID publish -
Expand Down Expand Up @@ -207,8 +207,13 @@ apart.
Which page shows and which differ is said in the headers and status line, for the reason above.
`r`, `[` and `]` are additive `DeviewKey` values, as `m` was: no `DEVIEW_VERSION` bump, and the
footer buttons reach the same commands from a shim built before them.
- DiffEngine offers the viewer `DocumentExtensions.Paged` only when `ViewerDocuments.Beside` finds
the folder by the resolved exe (beside, one up, or in the tool store behind a shim).
- DiffEngine offers the viewer `DocumentExtensions.Routed` only when `ViewerDocuments.Beside` finds
the folder by the resolved exe (beside, one up, or in the tool store behind a shim). That is
the paged formats and every map: a `.geojson` is no text extension to DiffEngine, unlike `.svg`.
- A map is drawn as an SVG is, one picture with no page commands (`DocumentFile.IsDrawn`). Its
text is the file for the text formats and GeoJSON read out of it for the binary ones
(`DocumentFile.IsSource`), so a FlatGeobuf is read by `DocumentWatch` as a PDF is but draws
as an SVG does. Those are two questions, and an SVG answering both the same way hid that.
- Text selection is a view, and makes the same bargain images do. A drag arrives as both of its
ends at once, in rows of the whole side rather than of the visible slice: a head knows the scroll
top it drew the press with, so only it can resolve one that spans a wheel notch, and reporting
Expand Down
5 changes: 3 additions & 2 deletions docs/diff-tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,9 @@ DiffTools.UseOrder(DiffTool.DiffEngineViewer);
whichever formats each platform's own decoder reads
* The standalone tool and the copy installed with DiffEngineTray also read PDF,
docx, xlsx and pptx files - as text, as pages drawn, or both - and draw SVGs
beside their text. Offered for those files only when the copy found is one of
these, never the bundled one, which stays small
and maps (GeoJSON, TopoJSON, KML, KMZ, GPX, WKT, WKB, FlatGeobuf and
GeoParquet) beside their text. Offered for those files only when the copy found
is one of these, never the bundled one, which stays small

#### Windows settings:

Expand Down
2 changes: 1 addition & 1 deletion docs/mdsource/tray.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ A delete is withdrawn when a later test run verifies against its file again, sin

When the tray holds it, the window becomes disposable. A viewer that is closed, killed or crashes takes nothing pending with it, and the tray opens a new one on the same queue. A snapshot arriving with no window open starts one.

The viewer installed with the tray also reads [documents](/docs/viewer.md#documents): PDF, Word, Excel and PowerPoint files as text, as their pages drawn, or both, and SVGs drawn beside their text. The copy bundled in the DiffEngine package does not. On a machine with the tray installed, test runs resolve the tray's copy ahead of the bundled one, so pending documents open in a viewer that can read them.
The viewer installed with the tray also reads [documents](/docs/viewer.md#documents): PDF, Word, Excel and PowerPoint files as text, as their pages drawn, or both, and SVGs and maps drawn beside their text. The copy bundled in the DiffEngine package does not. On a machine with the tray installed, test runs resolve the tray's copy ahead of the bundled one, so pending documents open in a viewer that can read them.

"Pending Snapshots" accepts all of them. Clicking one accepts that one, and its drop down offers discard, opening the viewer on it, and opening the source file. A snapshot that failed to apply is marked with `!` and stays pending, so it can be retried once whatever blocked it is out of the way.

Expand Down
26 changes: 23 additions & 3 deletions docs/mdsource/viewer.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ Accepting is the same act it is for text — copy the received file over the exp

## Documents

The standalone tool and the copy installed with [DiffEngineTray](/docs/tray.md) carry a `documents` folder, and with it read `.pdf`, `.docx`, `.xlsx` and `.pptx` files, and draw `.svg` files. The copy bundled in the DiffEngine package does not, to stay small: the folder is about 16 MB of libraries and 22 MB of natives per platform. That copy reads these files exactly as it always has, an SVG as text.
The standalone tool and the copy installed with [DiffEngineTray](/docs/tray.md) carry a `documents` folder, and with it read `.pdf`, `.docx`, `.xlsx` and `.pptx` files, and draw `.svg` files and [maps](#maps). The copy bundled in the DiffEngine package does not, to stay small: the folder is about 16 MB of libraries and 22 MB of natives per platform. That copy reads these files exactly as it always has, an SVG or a GeoJSON file as text.

A document is shown one of three ways, and `r`, or the button naming the next one, cycles between them:

Expand All @@ -199,7 +199,8 @@ A document is shown one of three ways, and `r`, or the button naming the next on

What the text is depends on the format:

* SVG: the file itself.
* SVG, and a map that is text: the file itself.
* A binary map: its features as GeoJSON.
* PDF: each page's text under a `--- page N ---` line, read with [PDFium](https://pdfium.googlesource.com/pdfium) through [Morph.PDFium](https://github.com/Papyrine/Morph.PDFium).
* Word, Excel and PowerPoint: the document as Markdown, from [Morph](https://github.com/Papyrine/Morph). Embedded pictures become `image-N` references rather than lines of base64.

Expand All @@ -213,7 +214,26 @@ Reading and drawing happen on a thread of their own once the window is up, so a

An SVG is drawn with scripts, external images and external elements turned off. A snapshot is test output, and nothing in one gets to reach the network or the disk.

DiffEngine offers the viewer for `.pdf`, `.docx`, `.xlsx` and `.pptx` only when the copy it resolved carries the folder. The viewer is last in the default tool order, so Word, Excel, Beyond Compare or DeltaWalker are still preferred where installed.
DiffEngine offers the viewer for `.pdf`, `.docx`, `.xlsx`, `.pptx` and the map extensions only when the copy it resolved carries the folder. The viewer is last in the default tool order, so Word, Excel, Beyond Compare or DeltaWalker are still preferred where installed.


### Maps

Maps are read and drawn with [GeoConvert](https://github.com/Papyrine/GeoConvert). Each is one picture, as an SVG is, so there are no pages to turn, and the status line says whether the two draw the same.

| Format | Extension | Text |
| --- | --- | --- |
| GeoJSON | `.geojson` | The file |
| TopoJSON | `.topojson` | The file |
| KML | `.kml` | The file |
| GPX | `.gpx` | The file |
| WKT | `.wkt` | The file |
| KMZ | `.kmz` | GeoJSON |
| WKB | `.wkb` | GeoJSON |
| FlatGeobuf | `.fgb` | GeoJSON |
| GeoParquet | `.geoparquet` | GeoJSON |

A map is drawn with its longer side 2048 pixels, in the projection GeoConvert picks for its extent. A map with no features is reported as having nothing to draw. Shapefiles are left out, being a set of files where a snapshot is one, and so are `.json`, `.csv` and `.parquet`, which hold far more than maps.


## With DiffEngineTray
Expand Down
2 changes: 1 addition & 1 deletion docs/tray.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ A delete is withdrawn when a later test run verifies against its file again, sin

When the tray holds it, the window becomes disposable. A viewer that is closed, killed or crashes takes nothing pending with it, and the tray opens a new one on the same queue. A snapshot arriving with no window open starts one.

The viewer installed with the tray also reads [documents](/docs/viewer.md#documents): PDF, Word, Excel and PowerPoint files as text, as their pages drawn, or both, and SVGs drawn beside their text. The copy bundled in the DiffEngine package does not. On a machine with the tray installed, test runs resolve the tray's copy ahead of the bundled one, so pending documents open in a viewer that can read them.
The viewer installed with the tray also reads [documents](/docs/viewer.md#documents): PDF, Word, Excel and PowerPoint files as text, as their pages drawn, or both, and SVGs and maps drawn beside their text. The copy bundled in the DiffEngine package does not. On a machine with the tray installed, test runs resolve the tray's copy ahead of the bundled one, so pending documents open in a viewer that can read them.

"Pending Snapshots" accepts all of them. Clicking one accepts that one, and its drop down offers discard, opening the viewer on it, and opening the source file. A snapshot that failed to apply is marked with `!` and stays pending, so it can be retried once whatever blocked it is out of the way.

Expand Down
26 changes: 23 additions & 3 deletions docs/viewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ Accepting is the same act it is for text — copy the received file over the exp

## Documents

The standalone tool and the copy installed with [DiffEngineTray](/docs/tray.md) carry a `documents` folder, and with it read `.pdf`, `.docx`, `.xlsx` and `.pptx` files, and draw `.svg` files. The copy bundled in the DiffEngine package does not, to stay small: the folder is about 16 MB of libraries and 22 MB of natives per platform. That copy reads these files exactly as it always has, an SVG as text.
The standalone tool and the copy installed with [DiffEngineTray](/docs/tray.md) carry a `documents` folder, and with it read `.pdf`, `.docx`, `.xlsx` and `.pptx` files, and draw `.svg` files and [maps](#maps). The copy bundled in the DiffEngine package does not, to stay small: the folder is about 16 MB of libraries and 22 MB of natives per platform. That copy reads these files exactly as it always has, an SVG or a GeoJSON file as text.

A document is shown one of three ways, and `r`, or the button naming the next one, cycles between them:

Expand All @@ -206,7 +206,8 @@ A document is shown one of three ways, and `r`, or the button naming the next on

What the text is depends on the format:

* SVG: the file itself.
* SVG, and a map that is text: the file itself.
* A binary map: its features as GeoJSON.
* PDF: each page's text under a `--- page N ---` line, read with [PDFium](https://pdfium.googlesource.com/pdfium) through [Morph.PDFium](https://github.com/Papyrine/Morph.PDFium).
* Word, Excel and PowerPoint: the document as Markdown, from [Morph](https://github.com/Papyrine/Morph). Embedded pictures become `image-N` references rather than lines of base64.

Expand All @@ -220,7 +221,26 @@ Reading and drawing happen on a thread of their own once the window is up, so a

An SVG is drawn with scripts, external images and external elements turned off. A snapshot is test output, and nothing in one gets to reach the network or the disk.

DiffEngine offers the viewer for `.pdf`, `.docx`, `.xlsx` and `.pptx` only when the copy it resolved carries the folder. The viewer is last in the default tool order, so Word, Excel, Beyond Compare or DeltaWalker are still preferred where installed.
DiffEngine offers the viewer for `.pdf`, `.docx`, `.xlsx`, `.pptx` and the map extensions only when the copy it resolved carries the folder. The viewer is last in the default tool order, so Word, Excel, Beyond Compare or DeltaWalker are still preferred where installed.


### Maps

Maps are read and drawn with [GeoConvert](https://github.com/Papyrine/GeoConvert). Each is one picture, as an SVG is, so there are no pages to turn, and the status line says whether the two draw the same.

| Format | Extension | Text |
| --- | --- | --- |
| GeoJSON | `.geojson` | The file |
| TopoJSON | `.topojson` | The file |
| KML | `.kml` | The file |
| GPX | `.gpx` | The file |
| WKT | `.wkt` | The file |
| KMZ | `.kmz` | GeoJSON |
| WKB | `.wkb` | GeoJSON |
| FlatGeobuf | `.fgb` | GeoJSON |
| GeoParquet | `.geoparquet` | GeoJSON |

A map is drawn with its longer side 2048 pixels, in the projection GeoConvert picks for its extent. A map with no features is reported as having nothing to draw. Shapefiles are left out, being a set of files where a snapshot is one, and so are `.json`, `.csv` and `.parquet`, which hold far more than maps.


## With DiffEngineTray
Expand Down
18 changes: 12 additions & 6 deletions src/DiffEngine.Tests/ViewerDocumentsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,33 +50,39 @@ public async Task Nowhere()
}

[Test]
public async Task DocumentsAreOfferedToACopyThatCanReadThem()
[Arguments(".pdf")]
[Arguments(".geojson")]
[Arguments(".fgb")]
public async Task DocumentsAreOfferedToACopyThatCanReadThem(string extension)
{
var viewer = Viewer("bin");
Documents(Path.Combine(root, "bin", "documents"));

await Assert.That(DetectedForPdf(viewer)).IsTrue();
await Assert.That(Detected(viewer, extension)).IsTrue();
}

[Test]
public async Task DocumentsAreNotOfferedToACopyThatCannot()
[Arguments(".pdf")]
[Arguments(".geojson")]
[Arguments(".fgb")]
public async Task DocumentsAreNotOfferedToACopyThatCannot(string extension)
{
var viewer = Viewer("bin");

await Assert.That(DetectedForPdf(viewer)).IsFalse();
await Assert.That(Detected(viewer, extension)).IsFalse();
}

/// <summary>
/// Through the resolution every launch takes, with the viewer found where the environment
/// variable that overrides its location says.
/// </summary>
static bool DetectedForPdf(string viewer)
static bool Detected(string viewer, string extension)
{
Environment.SetEnvironmentVariable("DiffEngine_DiffEngineViewer", Path.GetDirectoryName(viewer));
try
{
DiffTools.UseOrder(DiffTool.DiffEngineViewer);
return DiffTools.IsDetectedForExtension(DiffTool.DiffEngineViewer, ".pdf");
return DiffTools.IsDetectedForExtension(DiffTool.DiffEngineViewer, extension);
}
finally
{
Expand Down
5 changes: 3 additions & 2 deletions src/DiffEngine.Tests/diffTools.include.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,9 @@ DiffTools.UseOrder(DiffTool.DiffEngineViewer);
whichever formats each platform's own decoder reads
* The standalone tool and the copy installed with DiffEngineTray also read PDF,
docx, xlsx and pptx files - as text, as pages drawn, or both - and draw SVGs
beside their text. Offered for those files only when the copy found is one of
these, never the bundled one, which stays small
and maps (GeoJSON, TopoJSON, KML, KMZ, GPX, WKT, WKB, FlatGeobuf and
GeoParquet) beside their text. Offered for those files only when the copy found
is one of these, never the bundled one, which stays small

#### Windows settings:

Expand Down
2 changes: 1 addition & 1 deletion src/DiffEngine/DiffTools_Add.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static partial class DiffTools
if (diffTool == DiffTool.DiffEngineViewer &&
ViewerDocuments.Beside(resolvedExePath))
{
extensions.AddRange(DocumentExtensions.Paged.Except(extensions, StringComparer.OrdinalIgnoreCase));
extensions.AddRange(DocumentExtensions.Routed.Except(extensions, StringComparer.OrdinalIgnoreCase));
}

var tool = new ResolvedTool(
Expand Down
5 changes: 3 additions & 2 deletions src/DiffEngine/Implementation/DiffEngineViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ dropped instead
whichever formats each platform's own decoder reads
* The standalone tool and the copy installed with DiffEngineTray also read PDF,
docx, xlsx and pptx files - as text, as pages drawn, or both - and draw SVGs
beside their text. Offered for those files only when the copy found is one of
these, never the bundled one, which stays small
and maps (GeoJSON, TopoJSON, KML, KMZ, GPX, WKT, WKB, FlatGeobuf and
GeoParquet) beside their text. Offered for those files only when the copy found
is one of these, never the bundled one, which stays small
""");
}

Expand Down
47 changes: 37 additions & 10 deletions src/DiffEngine/Viewer/DocumentExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/// <para>
/// Linked into the viewer rather than written on both sides, for the reason
/// <see cref="ImageExtensions"/> is: DiffEngine offers a viewer that has the folder as the diff tool
/// for the paged ones, and the two lists drifting apart means a window full of mojibake.
/// for the routed ones, and the two lists drifting apart means a window full of mojibake.
/// </para>
/// </summary>
static class DocumentExtensions
Expand All @@ -21,21 +21,48 @@ static class DocumentExtensions
".xlsx"
];

/// <summary>
/// Maps whose text is the file, drawn by GeoConvert. Not text extensions to DiffEngine, so they
/// are routed as the paged ones are.
/// </summary>
public static readonly string[] TextMaps =
[
".geojson",
".gpx",
".kml",
".topojson",
".wkt"
];

/// <summary>
/// Maps whose text is what they read as in GeoJSON. Shapefile is left out: it is a set of files
/// and a snapshot is one, and CSV and Parquet hold more than maps.
/// </summary>
public static readonly string[] BinaryMaps =
[
".fgb",
".geoparquet",
".kmz",
".wkb"
];

/// <summary>
/// Text that also draws as a picture. Already a text extension to DiffEngine, so it is routed
/// nowhere new, and a viewer without the folder shows it as the text it is.
/// </summary>
public const string Drawn = ".svg";

static HashSet<string> paged = [with(Paged, StringComparer.OrdinalIgnoreCase)];

public static bool IsPaged(string path) =>
paged.Contains(Path.GetExtension(path));
/// <summary>
/// What DiffEngine offers a viewer with the folder for.
/// </summary>
public static readonly string[] Routed = [.. Paged, .. TextMaps, .. BinaryMaps];

public static bool IsDrawn(string path) =>
Path.GetExtension(path).Equals(Drawn, StringComparison.OrdinalIgnoreCase);
static HashSet<string> routed = [with(Routed, StringComparer.OrdinalIgnoreCase)];

public static bool Is(string path) =>
IsPaged(path) ||
IsDrawn(path);
public static bool Is(string path)
{
var extension = Path.GetExtension(path);
return routed.Contains(extension) ||
extension.Equals(Drawn, StringComparison.OrdinalIgnoreCase);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<PackageReference Include="Morph" />
<PackageReference Include="Morph.Skia" />
<PackageReference Include="Morph.PDFium" />
<PackageReference Include="GeoConvert" />
<!--
SkiaSharp's net10.0 group brings the Windows and macOS natives only. NoDependencies rather than
the plain Linux package, so the renderer needs no fontconfig on the machine: Morph finds fonts
Expand Down
Loading
Loading