- Rust 93.5%
- Shell 2.6%
- Python 1.7%
- Meson 1.6%
- CSS 0.6%
|
|
||
|---|---|---|
| .forgejo | Added issue templates | |
| data | Changelog changed | |
| nautilus | Nautilus extension | |
| po | Nautilus extension | |
| screenshots | Screenshots updated | |
| scripts | Version bump; changed permission scope | |
| src | Formatting | |
| .gitignore | Nautilus extension | |
| build.rs | Nautilus extension | |
| cargo-sources.json | Version bump and Flathub setup | |
| Cargo.lock | Nautilus extension | |
| Cargo.toml | Nautilus extension | |
| COPYING | Initial 1.0.0 commit | |
| me.fouquet.Stencil.json | Nautilus extension | |
| meson.build | Nautilus extension | |
| README.md | Link fixed | |
| SCREENSHOTS.md | Nautilus extension | |
Stencil
A powerful batch file renaming utility for GNOME, built with GTK4 and libadwaita.
Stencil lets you build a rename queue from stackable operations and preview every result live before renaming anything. Queues can be saved as presets, exported and imported as JSON, and any rename can be undone.
(See more screenshots in the Screenshots Gallery)
Features
Operations
Stack any combination of these operations, in any order:
- Number - add a sequential counter (configurable start, step, and padding)
- Insert Text - add text before, after, or at a specific position
- Find & Replace - literal text replacement
- Regular Expression - regex search and replace
- Change Case - lower, upper, title, or sentence case
- Trim & Remove - drop characters and clean up whitespace
- Date & Time - prefix or suffix a formatted timestamp
- Set Extension - change, normalize, or remove the file extension
Other notable features
- Live preview of every resulting filename, with conflict detection and a configurable overwrite policy
- Save queues as presets, with built-in presets to start from
- Import and export presets as JSON
- Undo any rename
- Accepts files and folders as parameters, which can be used in scripting (or for the Nautilus extension).
Installation
Flathub
Head to Stencil on Flathub to install it.
Flatpak bundle (Codeberg releases)
Each release has a Flatpak bundle attached. Download it and install with:
flatpak install --user ./Stencil-<version>-x86_64.flatpak
The bundle requires the GNOME 50 runtime, which Flatpak will offer to install from Flathub if it isn't present.
Sandbox and filesystem access
The Flatpak asks for broader permissions than a typical sandboxed app: filesystem access to the home directory and the common external/removable media mount points (/run/media, /media, /mnt), and access to GVfs (for network shares smb://, sftp:// ...). Unfortunately, this is currently required for a batch renaming utility:
- Files must be renamed in place. Without direct filesystem access, files picked through the file chooser arrive via the document portal as proxies under
/run/user/<uid>/doc/..., which cannot be renamed (attempting one ends up in a.xdp-...proxy file instead of renaming the original), so Stencil detects portal paths and refuses to touch them rather than risk corrupting anything. With direct access, the file dialog hands back real paths and renames work directly. Unfortunately, there is currently no portal that covers file renaming in the way Stencil needs. The access is limited to where most users keep files to rename: home directory and the usual external/removable media mounts (/run/media,/media,/mnt), rather than the full host filesystem. - GVfs access lets Stencil rename files on locations mounted through GNOME's GVfs, such as network shares, exactly like local files.
Running from GNOME Builder vs. the installed Flatpak
During development using GNOME Builder, you need to keep the permission issue in mind. When you press Run in GNOME Builder, the app executes in the build sandbox, which does not contain the manifest's finish-args, so there is no host filesystem access, and files added via the file dialog come in through the document portal. Stencil will list and preview them normally but refuse to rename, with a toast explaining why.
To test real renames, use either:
- the installed Flatpak (
flatpak-builder --user --install ...as below, then run it from the shell or app grid), which has the fullfinish-args; - or the native Cargo build (
cargo run), which runs unsandboxed.
Nautilus extension
If you want to open Stencil directly from GNOME Files (Nautilus), you can install an extension. See detailed instructions here.
Building
Requirements:
- Rust toolchain (stable)
- Meson ≥ 1.0
- GTK 4 ≥ 4.12 and libadwaita ≥ 1.8 (development packages)
- blueprint-compiler
glib-compile-schemas(part of GLib development tools)- Ninja
Flatpak (recommended)
The repository ships a Flatpak manifest at scripts/flatpak/me.fouquet.Stencil.json. With flatpak-builder installed:
flatpak-builder --user --install --force-clean build-dir scripts/flatpak/me.fouquet.Stencil.json
flatpak run me.fouquet.Stencil
Release bundle
To build the single-file .flatpak bundle that gets attached to Codeberg releases:
./scripts/make-bundle.sh
This builds the manifest into a local OSTree repo (./repo) and packs it into Stencil-<version>-<arch>.flatpak in the repository root. The bundle contains only the app itself (the GNOME runtime is downloaded from Flathub when the user installs it). Bundles are based on the current machine's architecture: building on an x86_64 machine produces an x86_64 bundle.
Native (Meson)
meson setup _build
meson compile -C _build
meson install -C _build
Meson calls Cargo through the bridge scripts in scripts/, so a single build covers both the Rust crate and the desktop integration files (icon, .desktop file etc).
Cargo only (development)
For quick iteration you can skip Meson entirely:
cargo run
The Cargo build script (build.rs) compiles the Blueprint UI files, bundles the GResource, and compiles the GSettings schema into the target directory, so the app runs uninstalled. You still need blueprint-compiler and glib-compile-schemas on your PATH, plus the GTK4/libadwaita development packages.
Running the tests
All rename logic lives in a pure-Rust library crate with no GTK dependency, so the test suite runs as ordinary unit tests:
cargo test
The tests are also registered with Meson (suites model, engine, and app), so this works too, including from GNOME Builder's test panel (I prefer having a one-click solution directly in the IDE):
meson test -C _build
Translations
Stencil is fully internationalized with gettext. User-facing strings in the Rust sources, the Blueprint UI files, the desktop entry, and the AppStream metainfo are all translatable. The message catalogs can be found in po/.
To add a new language (using German, de, as an example):
1. Make sure the template is up to date
meson setup _build
ninja -C _build stencil-pot
2. Create the catalog for your language
cd po
msginit --locale=de --input=stencil.pot --output=de.po
3. Translate the msgstr entries in de.po, then register the language in the LINGULAS file (for example, add "de"). Make sure to keep the file sorted alphabetically.
4. Build; the catalog is compiled and installed automatically
ninja -C ../_build
When you add or change source strings, always run ninja -C _build stencil-pot to refresh po/stencil.pot, then ninja -C _build stencil-update-po to merge the new strings into every existing .po. The list of files scanned for strings is po/POTFILES.in, so make sure to add new source files there.
Stencil is currently localized in English and German. Contributions for other locales are welcome.
Code overview
The project is split into a GTK-free core and a GTK layer on top:
src/
├── lib.rs Library crate root - the pure-Rust core (no GTK)
├── i18n.rs gettext wrappers shared by the whole crate
├── engine/ The rename pipeline
│ ├── mod.rs Filename handling, preview computation, overwrite policy
│ ├── operation.rs The operation catalog (OpKind) and per-operation logic
│ └── preset.rs Presets: built-in operation queues, JSON import/export
├── model/ Plain data types
│ ├── file_item.rs A file in the list: name, size, kind classification
│ ├── prefs.rs Preference value types
│ └── mocks.rs Mock data
├── main.rs Binary entry point
├── app/ The GTK4/libadwaita front-end
│ ├── application.rs AdwApplication subclass, actions, settings
│ ├── main_window/ Main window: file list, operation rows, presets, renaming
│ ├── preferences.rs Preferences dialog
│ └── fileops.rs Filesystem operations (rename execution, undo)
├── blueprints/ UI definitions in Blueprint markup (.blp)
└── style.css Custom styling
data/ Desktop file, AppStream metainfo, GSettings schema, icon
po/ Translations: POTFILES.in, LINGUAS, .pot template, .po catalogs
scripts/ Build scripts and the Flatpak manifest
nautilus/ Nautilus extension
The split is intentional: everything that decides what a file gets renamed to lives in the library crate (engine + model) and is covered by unit tests, while the binary only handles the presentation.
Planned features
Renaming based on file metadata is planned for future releases, like inserting values from a file's embedded metadata into the new name, such as:
- Images - Exif data (capture date and time, camera model, dimensions, ...)
- Music - tags (artist, album, title, track number, ...)
- Video - container metadata (recording date, resolution, duration, ...)
Ideas and requests are welcome on the issue tracker.
Contributions
Contributions are welcome! Please make sure your code passes cargo clippy without warnings before submitting a pull request. Due to the requirements set by Flathub, code generated fully or partially by Large Language Models (LLMs) such as ChatGPT, Copilot, Claude or similar tools cannot be accepted. Please ensure that all submitted code is written and understood by you, so it can be properly reviewed and maintained.
License
Stencil is released under the GNU General Public License v3.0 or later.