Conversation
This is the initial version, it does not fully work yet but it is a small POC
Previously the exec would be halting which caused problems
Aligns project name across build scripts and configuration files to reflect DLauncher branding. Updates README to clarify dependencies, improving consistency and onboarding for new contributors.
…mproved feature list in README
… and update usage in main
…pp reader storage
…onical core implementation
…lize config/cache paths
…llow bugfix/type)
* chore: fix CMake globs and ignore Qt autogen (.qt) artifacts * Add --dump, cache save and ensure dirs are created; refactor app reader storage * Remove duplicate app reader sources and update includes to canonical core implementation * Unify include paths to canonical src/ layout (use core/... and ui/...) * feat(core): add XDG helpers and FrequencyStore; use in main to centralize config/cache paths * chore(docs): add supported commit types (bugfix, type) to CONTRIBUTING.md
…NotShowIn in cache; add discovery test; debug logging for list population
There was a problem hiding this comment.
Pull request overview
This pull request introduces significant improvements to the build system, codebase architecture, and development workflow for the DLauncher application launcher. The changes focus on performance optimizations, better XDG standards compliance, improved testability, and enhanced developer tooling.
Changes:
- Added commitlint GitHub Actions workflow to enforce Conventional Commits standards
- Enhanced CMake build system with compile commands export, test building options, and strict warning flags
- Refactored application discovery with caching, precomputed search fields, string interning, and configurable scan paths
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/commitlint.yml | New workflow for commit message validation |
| CMakeLists.txt | Added build options (BUILD_TESTS, ENABLE_STRICT_WARNINGS), compile commands export, and test targets |
| CONTRIBUTING.md | Updated with commit message type aliases and conventions |
| .gitignore | Added Qt auto-gen artifacts directory |
| src/core/xdg.{h,cpp} | New XDG Base Directory specification helpers |
| src/core/intern.{h,cpp} | New string interning module for memory optimization |
| src/core/frequency_store.{h,cpp} | New frequency tracking abstraction |
| src/core/apps/readApps.{h,cpp} | Major refactor with caching, precomputed fields, system app filtering, and dump diagnostics |
| src/utils/json.hpp | Enhanced directory creation for save operations |
| src/ui/components/list.cpp | Added debug logging for UI diagnostics |
| main.cpp | Integrated XDG paths, FrequencyStore, and new CLI flags (--dump, --show-system) |
| test/discovery_test.cpp | New integration test for app discovery |
| src/components/appRow/appRow.h | Updated include path to new location |
| dump*.txt | Development diagnostic files |
| src/{apps,utils}/readApps.{h,cpp} | Removed old file locations |
Comments suppressed due to low confidence (5)
src/components/appRow/appRow.h:5
- The include path "core/apps/readApps.h" should be "src/core/apps/readApps.h" for consistency with the project's include path conventions and the CMake configuration which adds CMAKE_SOURCE_DIR to the include directories.
src/core/apps/readApps.cpp:175 - The DumpAndPrint function doesn't use the configurable desktopAppPaths member variable. Instead, it hardcodes a priorityDirs list (lines 172-175), which means calls to SetDesktopAppPaths won't affect this function's behavior. This inconsistency could lead to confusing results where LoadApps and DumpAndPrint scan different directories. Consider using the same path expansion logic from LoadApps (lines 39-55) to respect the configured paths.
void AppReader::DumpAndPrint(bool includeHidden, bool showSystem)
{
const char* home = getenv("HOME");
std::string homeStr = home ? std::string(home) : std::string();
std::vector<std::string> priorityDirs = {
homeStr + "/.local/share/applications",
"/usr/local/share/applications",
"/usr/share/applications"};
src/core/apps/readApps.cpp:329
- ReadDesktopApps and SearchApps should leverage the precomputed name_lc and exec_lc fields from DesktopApp. Currently, ReadDesktopApps calls toLower(app.name) on line 301, and SearchApps calls toLower(app.name) and toLower(app.exec) on lines 328 and 330. These fields are already computed during LoadApps and stored in app.name_lc and app.exec_lc, so reusing them would improve performance.
for (const auto &app : allApps)
{
if (searchTerm.empty() ||
toLower(app.name).find(searchLower) != std::string::npos)
{
filtered.push_back(app);
}
}
if (limit > 0 && filtered.size() > static_cast<size_t>(limit))
{
filtered.resize(limit);
}
return filtered;
}
const std::vector<DesktopApp> &AppReader::GetAllApps() const { return allApps; }
std::vector<DesktopApp> AppReader::SearchApps(std::string searchTerm, int limit,
bool isFuzzy)
{
std::vector<DesktopApp> results;
std::string searchLower = toLower(searchTerm);
if (isFuzzy)
{
std::set<std::pair<std::string, std::string>> seen;
for (const auto &app : allApps)
{
std::string appNameLower = toLower(app.name);
appNameLower.erase(remove_if(appNameLower.begin(), appNameLower.end(), ::isspace), appNameLower.end());
CONTRIBUTING.md:37
- The description for
type:on line 37 is unclear. It states "small project-specific type to indicate the change relates to 'type' metadata" but doesn't explain what "type metadata" means in the context of this project. Consider providing a clearer example or explanation, such as "type system changes" or "TypeScript type definitions" if that's what's meant, or clarify what project-specific metadata this refers to.
src/utils/json.hpp:105 - Redundant create_directories call on line 105. The parent directory was already created on line 89, so this call is unnecessary when the rename fails. This doesn't cause functional issues but is wasteful.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| static std::filesystem::path cachePath() | ||
| { | ||
| const char* xdg = getenv("XDG_CACHE_HOME"); | ||
| std::string base = xdg ? std::string(xdg) : (std::string(getenv("HOME")) + "/.cache"); | ||
| return std::filesystem::path(base) / "dlauncher" / "apps.cache"; | ||
| } | ||
|
|
||
| static void ensureCacheDir() | ||
| { | ||
| std::filesystem::create_directories(cachePath().parent_path()); | ||
| } |
There was a problem hiding this comment.
The cachePath() and ensureCacheDir() functions duplicate logic from the xdg module (src/core/xdg.h/cpp). Consider using xdg::cachePath("dlauncher/apps.cache") and xdg::ensureDir() instead of maintaining duplicate implementations. This would improve maintainability and ensure consistent behavior across the application.
| @@ -10,6 +10,7 @@ | |||
| #include "../../utils/json.hpp" | |||
| #include <fstream> | |||
There was a problem hiding this comment.
Duplicate #include <fstream> directive: the header is included on both lines 6 and 11. Remove one of these duplicates.
| #include <fstream> |
| GlobalEventListener globalKbListener(app); | ||
|
|
||
| // By default don't include NoDisplay/Hidden entries; allow override via CLI flag | ||
| // By default include all .desktop entries (don't skip NoDisplay/Hidden/OnlyShowIn) |
There was a problem hiding this comment.
The comment on line 50 is misleading or incorrect. It states "By default include all .desktop entries (don't skip NoDisplay/Hidden/OnlyShowIn)" but includeHidden is initialized to false on line 51, which means NoDisplay and Hidden entries WILL be skipped by default. Update the comment to accurately reflect the default behavior.
| // By default include all .desktop entries (don't skip NoDisplay/Hidden/OnlyShowIn) | |
| // By default skip NoDisplay/Hidden/OnlyShowIn .desktop entries; use --include-hidden/--show-hidden to include them |
| # gather commits; if RANGE is a single sha, handle that | ||
| if git rev-parse --verify "$RANGE" >/dev/null 2>&1; then | ||
| commits=$(git rev-list --no-merges $RANGE) | ||
| else | ||
| # fallback: recent 100 commits | ||
| commits=$(git rev-list --no-merges HEAD -n 100) | ||
| fi |
There was a problem hiding this comment.
The logic for handling commit ranges on lines 47-52 has a flaw. When RANGE is a single SHA (line 47), git rev-parse will verify that SHA exists and git rev-list will list just that one commit. However, when RANGE is something like "origin/main..HEAD" (line 26 or 35), git rev-parse --verify will fail because that's a range notation, not a single ref. This means the fallback on lines 50-51 will always trigger for push/PR events, checking the last 100 commits instead of just the new commits in the range. Use git rev-list directly without the rev-parse check, or use "git rev-list $RANGE 2>/dev/null || git rev-list HEAD -n 100".
| # gather commits; if RANGE is a single sha, handle that | |
| if git rev-parse --verify "$RANGE" >/dev/null 2>&1; then | |
| commits=$(git rev-list --no-merges $RANGE) | |
| else | |
| # fallback: recent 100 commits | |
| commits=$(git rev-list --no-merges HEAD -n 100) | |
| fi | |
| # gather commits; try the specified range, fall back to recent 100 commits if it is invalid | |
| commits=$(git rev-list --no-merges "$RANGE" 2>/dev/null || git rev-list --no-merges HEAD -n 100) |
| #include "../../utils/json.hpp" | ||
| #include <fstream> | ||
| #include <chrono> | ||
| #include "core/intern.h" |
There was a problem hiding this comment.
The include path "core/intern.h" should be "../core/intern.h" to be consistent with other includes in this file (lines 2 and 10 use "../" prefix). This inconsistency may cause build failures depending on the include path configuration.
| #include "core/intern.h" | |
| #include "../core/intern.h" |
| // cleanup | ||
| fs::remove(desktop); | ||
| fs::remove(tmp); |
There was a problem hiding this comment.
The test doesn't handle potential cleanup failures. If the test fails before reaching lines 34-35, the temporary directory and file will not be cleaned up. Consider using RAII or a try-catch-finally pattern to ensure cleanup happens even if the test fails. Alternatively, use std::filesystem::remove_all to recursively remove the directory and its contents in one call.
|
|
||
| add_executable(discovery_test test/discovery_test.cpp src/core/apps/readApps.cpp src/core/intern.cpp src/utils/utils.cpp) | ||
| target_include_directories(discovery_test PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/test) | ||
| target_link_libraries(discovery_test PRIVATE Qt6::Widgets) |
There was a problem hiding this comment.
The discovery_test executable (line 80) links against Qt6::Widgets but the test code doesn't use any Qt functionality - it only uses standard C++ libraries (filesystem, fstream, cassert) and the core app reader classes. This unnecessary dependency increases build time and binary size. Remove Qt6::Widgets from the target_link_libraries for discovery_test unless Qt functionality is actually required.
| target_link_libraries(discovery_test PRIVATE Qt6::Widgets) |
| @@ -1,4 +1,5 @@ | |||
| #include "list.h" | |||
| #include <iostream> | |||
| #include "list.h" | |||
There was a problem hiding this comment.
Duplicate include directive: "list.h" is included twice on lines 1 and 3. Remove one of these duplicate includes.
| #include "list.h" |
| ${CMAKE_SOURCE_DIR}/src/services | ||
| ${CMAKE_SOURCE_DIR}/src/components | ||
| ${CMAKE_SOURCE_DIR}/src/utils | ||
| ${CMAKE_SOURCE_DIR}/src/core |
There was a problem hiding this comment.
The target_include_directories has a duplicate entry: "${CMAKE_SOURCE_DIR}/src/core" appears on both line 65 and line 69. Remove the duplicate entry.
| ${CMAKE_SOURCE_DIR}/src/core |
| else if (!includeHidden && !app.onlyShowIn.empty()) | ||
| { | ||
| skipped = true; | ||
| reason = "OnlyShowIn"; | ||
| } | ||
| else if (!includeHidden && !app.notShowIn.empty()) | ||
| { | ||
| skipped = true; | ||
| reason = "NotShowIn"; | ||
| } |
There was a problem hiding this comment.
The DumpAndPrint logic for skipping based on OnlyShowIn and NotShowIn (lines 202-211) doesn't match the LoadApps logic. In LoadApps, these fields are parsed but never actually used to filter apps. Either LoadApps should also filter based on these fields, or the DumpAndPrint function shouldn't show them as skip reasons. This inconsistency means DumpAndPrint will report entries as "SKIPPED" that LoadApps would actually include.
| else if (!includeHidden && !app.onlyShowIn.empty()) | |
| { | |
| skipped = true; | |
| reason = "OnlyShowIn"; | |
| } | |
| else if (!includeHidden && !app.notShowIn.empty()) | |
| { | |
| skipped = true; | |
| reason = "NotShowIn"; | |
| } |
This pull request introduces several improvements to the development workflow, build configuration, and project documentation. The most significant changes are the addition of a commit message linting workflow, enhancements to the CMake build system (including new options for tests and warnings), and updates to the project's contribution guidelines to clarify commit message conventions.
Development workflow improvements:
.github/workflows/commitlint.yml) to enforce Conventional Commits for all pushes and pull requests targetingmainanddevbranches. This workflow checks commit messages for compliance, supporting both standard and project-specific types.Build system enhancements (CMake):
CMAKE_EXPORT_COMPILE_COMMANDSfor better tooling support (e.g., clang-tidy, language servers).BUILD_TESTS(to toggle building of unit tests) andENABLE_STRICT_WARNINGS(to enable strict compiler warnings for developer builds).src/and explicitly addmain.cppif present, reducing accidental inclusion of unrelated files.menu_parser_test,discovery_test) whenBUILD_TESTSis enabled, and enabled strict warning flags whenENABLE_STRICT_WARNINGSis set.Documentation and conventions:
CONTRIBUTING.mdto clarify accepted commit message types, including the addition ofbugfix:(as an alias forfix:) andtype:for project-specific metadata changes. The preferred types are now explicitly listed.Other:
dump2.txtcontaining application discovery results, likely for development or testing purposes.