Repository navigation
Conversation
e005a36 to
bc63295
Compare
bc63295 to
1d7a178
Compare
🦊 mika's reviewIncremental review: new commits since the last checkpoint. Summary
Change diagramflowchart LR
Entries["DesktopEntries"] --> Load["loadApps()"]
Open["Launcher opened"] --> Load
Load --> State["App list and appsLoaded"]
State -->|Empty: retry on next open| Open
Entries -->|Update while visible| Load
Estimated review effort: 1/5 · risk: low 📁 Walkthrough details
|
neur0map
left a comment
There was a problem hiding this comment.
🔴 Changes requested — 0 critical and 1 major issue(s): see the inline comments and the walkthrough for fixes and an agent-ready prompt.
| } | ||
| loadApps(); | ||
| appsLoaded = true; | ||
| // Note: appsLoaded is managed inside loadApps() — do NOT set it here |
There was a problem hiding this comment.
🟢 trivial · Maintainability · fix: low effort
The new comment contains an em dash, which the repository explicitly forbids in code and comments. Replace it with permitted punctuation so the change meets the mechanical commit gate.
Suggested change
| // Note: appsLoaded is managed inside loadApps() — do NOT set it here | |
| // loadApps() manages appsLoaded; do not set it here. |
| /** Mirrors loadApps() in Launcher.qml (lines 636-745). */ | ||
| function loadApps(state) { | ||
| const finalArr = state._desktopEntries.filter(e => !e.noDisplay); | ||
|
|
||
| state = { ...state, allApps: finalArr }; | ||
|
|
||
| // loadApps() is the sole authority over appsLoaded. | ||
| if (finalArr.length > 0) { | ||
| state = { ...state, appsLoaded: true }; | ||
| } else { | ||
| state = { ...state, appsLoaded: false }; | ||
| } | ||
|
|
||
| return state; | ||
| } | ||
|
|
||
| /** Mirrors Component.onCompleted (lines 142-153). */ | ||
| function onCompleted(state) { | ||
| state = loadApps(state); |
There was a problem hiding this comment.
🟠 major · Tests · fix: high effort
These tests exercise a separate JavaScript implementation, not Launcher.qml. Restoring either unconditional appsLoaded = true assignment in the QML leaves this suite passing, so it cannot catch the regression it claims to cover; exercise the actual QML component or its shared production logic instead.
| /** Mirrors Component.onCompleted (lines 142-153). */ | ||
| function onCompleted(state) { | ||
| state = loadApps(state); | ||
| // Note: appsLoaded is managed inside loadApps() — do NOT set it here |
There was a problem hiding this comment.
🟢 trivial · Maintainability · fix: low effort
The added test comments contain em dashes, which the repository forbids in code and comments. Replace them with permitted punctuation to meet the mechanical commit gate.
1d7a178 to
76cad43
Compare
neur0map
left a comment
There was a problem hiding this comment.
🔍 mika reviewed this change; details in the walkthrough comment.
| `false` and the next open retries. The Files tab is also restored: a previous | ||
| patch had replaced its `executeFileSearch` call with dead retry logic | ||
| (`python/launcher/Launcher.qml`). |
There was a problem hiding this comment.
🟡 minor · Possible Bug · fix: low effort
The changelog says this PR restores the Files tab, but the diff makes no change to its executeFileSearch call. Remove that claim unless the restoration is included in this PR.
There was a problem hiding this comment.
True, my bad. It's a good system that you built
76cad43 to
cd0a629
Compare
neur0map
left a comment
There was a problem hiding this comment.
🔍 mika reviewed this change; details in the walkthrough comment.
| - **The app launcher no longer shows an empty list when opened immediately | ||
| after login.** `loadApps()` is now the sole authority over the `appsLoaded` |
There was a problem hiding this comment.
🟡 minor · Possible Bug · fix: low effort
The launcher can still open with an empty list if scanning has not finished; the new retry happens on a later open or a desktop-entry change. Reword this claim to describe recovery rather than saying the empty list no longer appears.
There was a problem hiding this comment.
A little bit picky tho, but right
DesktopEntries.applications loads asynchronously when Quickshell starts. If the launcher was opened before the scan of /usr/share/applications completed, loadApps() received an empty array but appsLoaded was still set to true in two callers (Component.onCompleted and onIsVisibleChanged), preventing any subsequent retry. Root causes fixed: 1. Component.onCompleted: unconditional appsLoaded = true after loadApps() overrode the empty-result state set inside loadApps(). Removed. 2. onIsVisibleChanged show-branch: same unconditional override after loadApps() call. Removed. 3. loadApps() flag ownership: the function now sets appsLoaded=true when finalArr.length > 0, and appsLoaded=false when empty, in both branches. Callers no longer touch the flag. Result: on every launcher open, if allApps is still empty the next close-and-reopen or any DesktopEntries signal emitted while the launcher is closed sets appsLoaded=false, so the next open retries. No timers, no polling, zero overhead. Adds appindex.test.mjs: 10 regression tests covering the race condition, evaluating Launcher.qml handlers directly via node:vm. Red-green verified: tests fail when the original bugs are restored. Note: Fixed: the app launcher recovers when opened before desktop entries finish scanning
cd0a629 to
f28b1e7
Compare
What changed
The app launcher (Super+Space) would sometimes open with a completely empty
list. This happened at startup in a narrow race window: if the launcher was
opened before Quickshell finished scanning
/usr/share/applications,loadApps()received an empty array — butappsLoadedwas still set totrueunconditionally in two callers, so the launcher never retried.Four bugs found and fixed in
python/launcher/Launcher.qml:Component.onCompleted— unconditionalappsLoaded = trueafterloadApps()overrode the empty-result state the function had just set.Removed;
loadApps()is now the sole authority over the flag.onIsVisibleChangedshow-branch — same unconditional override. Removed.onIsVisibleChangedelse-branch —executeFileSearch("")was replaced byretry logic that never called it and tried to reload apps while on the
Files tab, breaking file search entirely. Restored the original call.
loadApps()flag ownership — the function now setsappsLoaded = truewhen
finalArr.length > 0andappsLoaded = falseotherwise, coveringboth branches explicitly. No early
return.The existing
ConnectionstoDesktopEntries(onValuesChanged,onCountChanged,onApplicationsChanged) already setappsLoaded = falsewhen the launcher is hidden, so the next open always retries when needed.
No timers, no polling, zero extra overhead.
Also adds
appindex.test.mjswith 10 regression tests covering the racecondition and edge cases (noDisplay entries, rapid open/close, reactive
refresh while open).
Area
ryoku
How it was tested
qmllinton the changed file: clean.bin/ryoku-dev-scan-slop: clean.appindex.test.mjs: 10/10 pass with the fix; 2/10 fail when theoriginal bug is restored (red-green verified).
appsLoaded(onCompleted,onIsVisibleChanged,loadApps(), all fourConnectionsblocks) and confirmed to be logically consistent in everyscenario including launcher-open-during-scan and rapid open/close bursts.
Checklist
[area] scope: summarycommit subject.CHANGELOG.mdupdated in the area I touched.--no-verify.luac -p), shell scripts passbash -n, and QML passesqmllintwhere applicable.