v0.8.1
Before you double-click
This build is not signed or notarized, so macOS blocks the first launch. Allow it once:
- macOS 15 Sequoia and later — double-click, dismiss the warning, then open
System Settings ▸ Privacy & Security and click Open Anyway. Apple removed the
Control-click shortcut for unsigned apps in macOS 15, so right-clicking does not help.- macOS 13–14 — right-click the app ▸ Open, then confirm.
Only the first launch asks.
Macros, worked through against the three things the first person to use them ran into — same day as 0.8.0, which is when a feature is most worth fixing.
The recorder read what had already happened and left you to work out which of the last thirty things
was the job — the one question you can answer and the list cannot. It now has two ends you press
yourself. It also told people who had just made three folders that nothing had happened, because what
you do by hand is read back out of a history that can be switched off; the new recording does not
depend on it. And each macro is its own file now, because a macro is a thing people hand to each other
and getting one out of a JSON array meant editing by hand — which is also why one typo no longer costs
you every macro you have.
Added
-
Macros can be recorded with a beginning and an end. "Macro from Recent Actions…" offered the last
thirty things that happened and left the reader to work out which of them was the job — the one
question they could answer and the list could not. Configuration ▸ Macros… ▸ Record Macro… now
arms a recording: a small floating panel says it is running and counts the steps as they happen, and
Stop and Save… offers back exactly what fell between the two presses, already ticked. Discard
throws it away. It is also the commandcm_MacroRecord, so it can go on a key or a button — a
recording is armed before the work and stopped after it, and having to open a window at each end was
most of the friction. Reading what recently happened is still there, as From Recent Actions… in
the same window. -
A recording survives a restart. It is armed by hand and then the user goes off and works, so
quitting in the middle of one is not a decision to throw it away, and a crash certainly is not. The
running recording is written tomacro-recording.jsonas it goes and picked up at the next launch:
the indicator comes back with the steps it had and says where it came from. The file is deleted the
moment a recording ends, so its presence is the whole question and an ordinary launch does no work. -
A new file (Shift+F4) can be recorded. It could not be, and recording it as
write_filewould
have been worse than not recording it:write_filecreates or truncates, so the macro would have
emptied an existing file the second time it ran. The catalogue has acreate_filealongside it —
creates when the name is free, leaves an existing file alone, never overwrites — which is what the
panel does and what the assistant was missing for "make me an empty file". -
The macro window can run a macro. Trying one you have just recorded meant closing the window and
going to find the command. Run does it on the panels behind the window, through the same plan and
the same confirmation as every other way in — the window has no privileges of its own.
Changed
-
Each macro is its own file:
macros/<id>.json. They lived in onemacros.json, which followed
the other preset stores — and a macro is not a preset. It is a thing people hand to each other, and
getting one out of a JSON array, or into one, meant editing by hand. The project already draws this
line elsewhere and says why:scripts/keeps one file per script because a script is something a
person opens in Script Editor. Amacros.jsonfrom an earlier version is moved across at the first
launch — order and any_commentnotes intact — and renamedmacros.json.migrated; nothing reads
it afterwards. Order lives in anorderkey per file, since a directory has none of its own, and a
file dropped in by hand lands at the end. -
Macros can be exported and imported. Export… in the macro window writes the selected macro to
a file of its own; Import… adds macros from files somebody sent you, and reads both shapes — a
single macro and a whole oldmacros.json. An import never replaces: a macro whose id is taken gets
a free one (backuparriving beside yours becomesbackup-2), and the ids the new ones ended up
with are named, because the button you make next has to point at the right one. -
The macro window is narrower, and reordering is two arrows. Adding Run and Export to the row of
actions had pushed it wide. Move Up and Move Down are now ↑ and ↓ — the two whose meaning an
arrow carries completely; the rest stay words, because a row of icons would trade a wide window for
a guessing game. The arrows keep their names for VoiceOver, the tooltip and the layout report. -
Macros are one menu entry instead of three. Recording a macro, listing the macros and editing the
file were three siblings under Configuration, which made the menu ask a question nobody has — which
of these three is the macros one — and hid the ordinary case behind a choice. Configuration ▸
Macros… opens the list; the other two are buttons in it. Both commands stay registered, so a key,
a toolbar button or a.mnuentry already pointing at one still works.
Fixed
-
Pressing Escape during an in-cell rename stopped that panel from ever showing another folder.
Renaming in place suspends the panel's table updates so the field editor cannot be torn down under
the typing; that suppression was lifted in the commit callback, and cancelling with Escape never
called it. From then on the panel drew nothing new for the rest of the session — and drew nothing
new silently: it went on loading directories, the tab, the breadcrumb and the status bar's path
all followed, so..moved everything except the list of files and the panel appeared to be stuck
in the folder. The editor now reports back on every way out, cancel included, and it also says
whether it opened at all — the same dead panel was reachable from that end too, and one of the two
had already been reached. A VM scenario presses Escape and then navigates. -
Going up into a folder you may not read moved the tab there anyway. Every other navigation has
waited for the listing to arrive before the tab follows it; Ctrl+PageUp did not, and it is the one
navigation where an unreadable destination is likely — the folder you are in is readable, that is
how you got into it, and the one above it need not be. The panel stayed put, the tab named the
parent, and the session is written from the tab, so the next launch opened at a folder it could not
list. Measured with the guard taken back out: the panel reported the child while its tab said
lockedandTab0Pathhad been written to the parent. A VM scenario walks up out of a folder whose
parent is mode 000. -
Back and Forward counted from the wrong place after a folder had been deleted. The per-panel
back/forward position moved before the folder was loaded and never took the answer into account, so
a place that had been deleted, ejected or unmounted since you were there left the position one step
away from the panel — and the next press then counted from there and landed somewhere nobody had
asked for. Worse, the dead entry was a wall: every further press in that direction arrived at the
same missing folder and got no further past it. Back, Forward and the Alt+Down history list now
share one path that puts the position back, and an entry that cannot be opened is dropped, so the
next press reaches what was behind it. A folder that merely lost the race — you navigated again
while it was loading — keeps its place: that case is now told apart from a refusal instead of both
arriving as a bare "false", which is what made discarding an entry safe to do at all. -
A tab whose folder had been deleted showed you a different tab's files. Switching to a tab loads
the folder it remembers, and when that failed the panel simply stayed as it was — so the previous
tab's contents sat under the new tab's title, and the same thing greeted you at startup for a tab
left on a disk that was not mounted yet. This is the one navigation that cannot answer by standing
still, because the tab has already changed by the time the panel is asked to follow it. It now
retreats to the nearest folder above the missing one that can actually be opened — two levels up if
that is what it takes — and moves the tab there, so the title and the files agree again. -
The macro recorder reported "nothing has happened yet" to people who had just done four things.
What you do by hand was read back out of the global history — and the history can be switched off in
Settings ▸ Misc. WithHistory.Enabled=0the recorder was silently blind, and the message sent the
user off to repeat work that was never going to be recorded. The new recording does not read the
history at all: the panels report each finished operation to it directly, from the same line that
feeds the history, so one cannot be reached without the other. The old path still needs the history,
and now says so and names the switch instead of blaming the user. -
A sentence, not the buttons, decided how wide the macro window opened. The explanatory line
under the list is a wrapping label, and a wrapping label answers its fitting size as one line
unless it is given apreferredMaxLayoutWidth— so it asked for 869pt while the widest row of
buttons needed 781. The buttons set the width now and the sentence wraps into it; the window opens
at 781 instead of 889. The layout report measures both rows and the note, so the next time something
quietly widens this window it says which of the three did it. -
One typo in the macros file cost every macro in it. The file was decoded in one go, which is
all-or-nothing, so a single entry with"steps"written as a string left the user with no macros —
and with every button, key and menu entry that ran one silently doing nothing. Measured: three
entries, one broken, nothing loaded. Entries are now read one at a time, so a bad one costs only
itself and is reported by name — which is what the rest of the store already did for an unusable id,
a duplicate and an empty macro. One file per macro (above) makes that structural: a file that will
not parse cannot take its neighbours with it. -
The recording indicator's Discard button read "Cancel changes" in some languages. It reused the
sharedDiscardstring, which several translators had — correctly, for its own context — rendered as
the answer to "save your changes?". A recording is not a change to save, so it has its own string now. -
The recording indicator counted "1 steps". The same defect as the confirmation dialog's
"step(s)", caught before it shipped: the label carries plural variations in all nineteen languages,
taken from the ones the translators had already written for the run-a-macro heading. -
Tools/check-format-specifiers.pyreported every pluralized string as broken.%#@steps@names
an argument whose type is declared beside the value; read literally it looks like a#-flagged%@,
so the gate claimed each of the nineteen translations passed a pointer where the code passes an
integer. It now expands the token to the specifier the entry declares, and the gate is green. -
The quick preview stopped following the cursor after a Markdown or HTML file. A lister plugin's
view is added on top of the preview's own renderers and is opaque, and it was taken away only when a
file fell through to Quick Look. So the next picture, PDF or word-processor document was drawn
behind a web view that was still there: the name, kind and dates under the preview went on updating
with every selection while the picture did not change — including across panels, which made it look
like the preview had bound itself to one side of the window. A plain text file recovered by itself,
which is what made the state hard to read. The plugin view is now put away whenever the next file is
not the plugin's, and the automation report names it ahead of the other renderers, because it is what
is on screen when it is there. -
The macro confirmation dialog counted in "step(s)". It read "Run the macro “Backup” — 2 step(s)."
and the parenthetical had been carried into thirteen translations that inflect the noun properly —
krok(ů),шаг(ов),pas(pași). It is a real plural now, with the categories each language
distinguishes:one/few/manyfor Russian, Ukrainian and Polish,one/two/few/otherfor Slovenian,
and Romanian'sdeabove nineteen.The string was not the whole defect.
String(format:)over a format fetched byString(localized:)
cannot expand%#@…@— the plural is resolved by the lookup, so the lookup has to be the thing
that knows the count. Fetching first and formatting afterwards would have printed the substitution
marker verbatim, which is why the parenthetical was there in the first place. The call site
interpolates instead.A missing plural category does not fail loudly, it falls through to
other— Russian said "5 шага"
and Czech "2 kroků" in a first attempt at this, and both look plausible in a diff.
check-translations.pynow gates the categories, verified by putting a missing one back.
Documentation
-
Macros are now shown, not only described. The feature shipped in 0.8.0 with a thorough reference
page and no picture on it — the one page in Power tools without one — while the homepage did not
mention macros at all and the README listed AppleScript but not them. Three real screenshots now
carry it: the confirmation dialog with its steps resolved against the panels, the recorder offering
what just happened, and the manager with every macro's command name and permission. Two of the three
are dialogs the framebuffer cannot reach —NSAlert.runModal()holds the main queue, so the
automation script never gets to the verb that would photograph them — socapture.pylearnedenv:
andpull:, and the app's ownPC_MACRO_*_SHOTprobes draw them. They are specs like every other
screenshot, regenerable on the next release rather than taken by hand. -
A macro tutorial, which the six existing ones lacked: do it once, let the recorder offer it back,
tick Follow the panels so it works tomorrow, read the plan, put it on a key — then open the file
and see what was written, ending at the one thing the recorder cannot give you,%{ask:…}. -
Two things the help page had wrong. It said the file is seeded with seven worked examples while
listing eight and shipping eight, in all nineteen languages. And it said "strike out a step you do not
want; what is left is what runs", which is not what happens: striking one out takes its dependants
with it, and a reader whose checkboxes moved on their own had nothing to read about it. -
Macros reached the homepage, the README, the feature inventory (F-477 and F-478 had no rows at all)
and the menu reference; and the four help topics macros already named as related — the button bar, the
Start menu, shortcuts and the assistant — now point back, the assistant's page from the very section
that describes the log the recorder reads.