Repository navigation
Architecture
Two projects and a line between them. SpaceSharp.Core targets plain net10.0 and cannot reference Avalonia, Velopack or Win32 (the compiler enforces it: none of them exist for that target). SpaceSharp is the app on top. The rule when adding code: if it would work the same on every platform, it goes in Core; anything that draws, opens a window, talks to the shell, the trash, the registry or the NTFS file table stays in the app.
scan ─────▶ FsNode tree ─────▶ Squarify + Grouping ─────▶ TreemapControl (render, zoom, input)
│ │ │
│ ├──▶ FileFilter (dims the map) ├──▶ MainWindow partials: FilterPanel, Insights, Changes, Scans, Tooltip, StatusBar, PalettePicker
│ ├──▶ DriveInsights (the Insights cards)
│ ├──▶ ScanCompare (baselines + gone items)
│ └──▶ ScanFile (.sscan save and load)
└── FolderWalker (every platform) / MftScanner + ElevatedScan (Windows, NTFS)
The tree (Core/Models/FsNode.cs). One node per file and folder: name, kind, size, size on disk, file count, last write time, attributes, and after a comparison the baseline sizes. Folders sum their children once in FinishDirectory. Memory matters at a million nodes, so fields are compact and the free-space box is a node like any other.
Scanning. FolderWalker is the System.IO scan every platform has, parallel, with exclusions and hard-link detection behind IPlatformFiles. On Windows a whole NTFS drive goes through MftScanner, which reads the master file table as one stream, verifies every record, and builds the tree from it; ElevatedScan runs it in a second elevated copy of the exe and streams the tree back over a pipe. While a walk runs, LiveTree keeps a thread-safe ledger of finished folders and stand-ins so the map can draw itself.
Layout (Core/Layout/Squarify.cs, Grouping.cs). The squarified treemap algorithm (Bruls, Huizing and van Wijk) on a UI-free LayoutRect. Grouping decides which small children become one "312 files" box according to Density.
Rendering and zoom (Controls/TreemapControl*.cs). One custom Avalonia control in six partial files (fields, camera, layout, render, input, live). It draws every box itself in two render passes rather than creating a control per box, which is why tens of thousands of boxes stay fast. Zoom re-lays out the visible folder rather than scaling a picture; the camera animates between layouts, and the live map tweens boxes between snapshots by path.
Filter (Core/Services/FileFilter.cs, MainWindow.FilterPanel.cs). Text is parsed into a FilterSpec; the tree is evaluated once per change and a folder stays lit when anything inside it matches. The drawer and the rail both write the same text.
Insights (Core/Services/DriveInsights.cs, MainWindow.Insights.cs). Pure, tested functions: bytes by type, by month, the cleanup suggestions (name patterns in CachePatterns), change totals, the free-space projection. The window only arranges cards.
Changes (Core/Services/ScanCompare.cs, MainWindow.Changes.cs). ScanCompare.Apply walks two trees matching names within each folder, writes baseline sizes onto the current nodes and returns a ScanComparison holding what is gone per folder. The view is a virtualized table over that.
Saved scans (Core/Services/ScanFile.cs). A gzip-compressed binary of the tree with a header (root, time, method, free space). Autosaves live per root, with a .prev copy for comparison.
Strings (Core/Resources/Strings*.resx, Core/Util/Strings.cs). Every user-visible string is a key; LocalizationTests fails the build when code asks for one the English file lacks, and a key missing from a translation falls back to English. Eighteen files, discovered by culture code at startup.
Settings and looks (Core/Util/AppSettings.cs, UiLooks.cs, App.axaml, Themes/Styles.axaml). Settings are a JSON file loaded once; every control style references colors through DynamicResource, so a theme or look change is a dictionary swap.
| To add | Touch |
|---|---|
| A setting | A property with a default in AppSettings (and ResetToDefaults), a row in SettingsWindow.Build(), its effect in MainWindow.ApplySettings() or ApplyLook(), the Settings reference
|
| A shortcut |
MainWindow.OnKeyDown, the list in ShortcutsWindow.cs, the README table, the Keyboard shortcuts page |
| UI text | A key in Strings.resx and the same key in all seventeen translation files |
| A built-in palette |
BuildSchemes() in Util/Palette.cs with twelve folder colors and a PaletteAbout_ string |
| A file type |
FileCategories in Core/Util/FileCategory.cs; the filter's words in FileFilter.TypeWords
|
| A cleanup pattern |
CachePatterns in DriveInsights.cs and a Cleanup_ string pair |
| An icon | A line in tools/make-icons.py's table (Lucide), which regenerates Themes/Icons.axaml
|
| A translation | One more Strings.<culture>.resx with a Meta_MachineTranslated entry; it appears in the language list on its own (Translating) |
DEVELOPING.md in the repository goes deeper on each of these and is kept in step with the code.
These pages describe SpaceSharp 2.5. Something wrong or missing? Edit the page or open an issue. · Changelog · spacesharp.app
Using SpaceSharp
- Getting started
- Reading the map
- Navigating
- The filter
- Insights
- Changes
- Inspect
- Cleaning up
- Saved scans and the start screen
- Settings reference
- Palettes and looks
- Custom palettes
- Keyboard shortcuts
- Command line
- Languages
Questions and problems
For contributors