mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
refactor: all your string_utils belongs to me
This commit is contained in:
@@ -838,18 +838,6 @@ std::vector<std::string_view> HyprlandWorkspaceBackend::parseEventArgs(std::stri
|
||||
return args;
|
||||
}
|
||||
|
||||
std::string HyprlandWorkspaceBackend::quoteCommandArg(const std::string& value) {
|
||||
std::string escaped = "\"";
|
||||
for (const char c : value) {
|
||||
if (c == '\\' || c == '"') {
|
||||
escaped.push_back('\\');
|
||||
}
|
||||
escaped.push_back(c);
|
||||
}
|
||||
escaped.push_back('"');
|
||||
return escaped;
|
||||
}
|
||||
|
||||
Workspace HyprlandWorkspaceBackend::toWorkspace(const WorkspaceState& state) {
|
||||
const std::uint32_t coord =
|
||||
state.id >= 0 ? static_cast<std::uint32_t>(state.id - 1) : static_cast<std::uint32_t>(state.ordinal);
|
||||
|
||||
@@ -84,7 +84,6 @@ private:
|
||||
[[nodiscard]] static std::optional<std::uint64_t> parseHexAddress(std::string_view value);
|
||||
[[nodiscard]] static std::optional<int> parseInt(std::string_view value);
|
||||
[[nodiscard]] static std::vector<std::string_view> parseEventArgs(std::string_view data, std::size_t count);
|
||||
[[nodiscard]] static std::string quoteCommandArg(const std::string& value);
|
||||
[[nodiscard]] static Workspace toWorkspace(const WorkspaceState& state);
|
||||
|
||||
OutputNameResolver m_outputNameResolver;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "compositors/sway/sway_runtime.h"
|
||||
#include "core/log.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <cerrno>
|
||||
@@ -203,12 +204,6 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
std::string toLowerCopy(std::string value) {
|
||||
std::transform(value.begin(), value.end(), value.begin(),
|
||||
[](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string assignmentLookupKey(std::string_view workspaceKey, std::string_view appId, std::string_view title) {
|
||||
std::string key;
|
||||
key.reserve(workspaceKey.size() + appId.size() + title.size() + 2);
|
||||
@@ -272,7 +267,7 @@ void SwayWorkspaceBackend::activate(const std::string& id) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendMessage(kIpcRunCommand, "workspace " + quoteCommandArg(id));
|
||||
sendMessage(kIpcRunCommand, "workspace " + StringUtils::quoteDouble(id));
|
||||
}
|
||||
|
||||
void SwayWorkspaceBackend::activateForOutput(wl_output* /*output*/, const std::string& id) { activate(id); }
|
||||
@@ -352,7 +347,7 @@ SwayWorkspaceBackend::assignTaskbarWindows(const std::vector<TaskbarWindowCandid
|
||||
std::unordered_map<std::string, std::vector<const WorkspaceWindow*>> windowsByLookupKey;
|
||||
windowsByLookupKey.reserve(outputWindows.size());
|
||||
for (const auto& window : outputWindows) {
|
||||
const std::string appIdLower = toLowerCopy(window.appId);
|
||||
const std::string appIdLower = StringUtils::toLower(window.appId);
|
||||
windowsByLookupKey[assignmentLookupKey(window.workspaceKey, appIdLower, window.title)].push_back(&window);
|
||||
}
|
||||
|
||||
@@ -376,7 +371,8 @@ SwayWorkspaceBackend::assignTaskbarWindows(const std::vector<TaskbarWindowCandid
|
||||
}
|
||||
|
||||
for (const auto& candidateAppId : window.appIds) {
|
||||
const std::string lookupKey = assignmentLookupKey(workspaceKey, toLowerCopy(candidateAppId), window.title);
|
||||
const std::string lookupKey =
|
||||
assignmentLookupKey(workspaceKey, StringUtils::toLower(candidateAppId), window.title);
|
||||
auto it = windowsByLookupKey.find(lookupKey);
|
||||
if (it == windowsByLookupKey.end()) {
|
||||
continue;
|
||||
@@ -667,15 +663,3 @@ Workspace SwayWorkspaceBackend::toWorkspace(const SwayWorkspace& workspace) {
|
||||
.occupied = workspace.occupied,
|
||||
};
|
||||
}
|
||||
|
||||
std::string SwayWorkspaceBackend::quoteCommandArg(const std::string& value) {
|
||||
std::string escaped = "\"";
|
||||
for (const char c : value) {
|
||||
if (c == '\\' || c == '"') {
|
||||
escaped.push_back('\\');
|
||||
}
|
||||
escaped.push_back(c);
|
||||
}
|
||||
escaped.push_back('"');
|
||||
return escaped;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ private:
|
||||
void requestTree();
|
||||
void refreshFromWorkspaceEvent();
|
||||
[[nodiscard]] static Workspace toWorkspace(const SwayWorkspace& workspace);
|
||||
[[nodiscard]] static std::string quoteCommandArg(const std::string& value);
|
||||
|
||||
OutputNameResolver m_outputNameResolver;
|
||||
compositors::sway::SwayRuntime& m_runtime;
|
||||
|
||||
+3
-15
@@ -1,6 +1,7 @@
|
||||
#include "config/cli.h"
|
||||
|
||||
#include "core/toml.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
@@ -39,19 +40,6 @@ namespace noctalia::config {
|
||||
bool force = false;
|
||||
};
|
||||
|
||||
std::string shellQuote(std::string_view raw) {
|
||||
std::string out = "'";
|
||||
for (const char c : raw) {
|
||||
if (c == '\'') {
|
||||
out += "'\\''";
|
||||
} else {
|
||||
out.push_back(c);
|
||||
}
|
||||
}
|
||||
out.push_back('\'');
|
||||
return out;
|
||||
}
|
||||
|
||||
bool writeTextFile(const std::filesystem::path& path, std::string_view content, std::string& error) {
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(path.parent_path(), ec);
|
||||
@@ -257,8 +245,8 @@ namespace noctalia::config {
|
||||
std::printf("Config home: %s\n", configHome.string().c_str());
|
||||
std::printf("State home: %s\n\n", stateHome.string().c_str());
|
||||
std::printf("Run with:\n");
|
||||
std::printf(" XDG_CONFIG_HOME=%s XDG_STATE_HOME=%s %s\n", shellQuote(configHome.string()).c_str(),
|
||||
shellQuote(stateHome.string()).c_str(), shellQuote(argv0).c_str());
|
||||
std::printf(" XDG_CONFIG_HOME=%s XDG_STATE_HOME=%s %s\n", StringUtils::shellQuote(configHome.string()).c_str(),
|
||||
StringUtils::shellQuote(stateHome.string()).c_str(), StringUtils::shellQuote(argv0).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
#include "core/files/directory_scanner.h"
|
||||
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <numeric>
|
||||
#include <system_error>
|
||||
|
||||
namespace {
|
||||
|
||||
std::string lowerText(std::string_view text) {
|
||||
std::string out;
|
||||
out.reserve(text.size());
|
||||
for (char ch : text) {
|
||||
out.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(ch))));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<FileEntry> DirectoryScanner::scan(const std::filesystem::path& dir,
|
||||
const std::vector<std::string>& extensions, bool showHiddenFiles,
|
||||
FileDialogSortField sortField, FileDialogSortOrder sortOrder) const {
|
||||
@@ -92,7 +80,7 @@ std::vector<FileEntry> DirectoryScanner::scan(const std::filesystem::path& dir,
|
||||
std::vector<std::string> lowerNames;
|
||||
lowerNames.reserve(entries.size());
|
||||
for (const auto& entry : entries) {
|
||||
lowerNames.push_back(lowerText(entry.name));
|
||||
lowerNames.push_back(StringUtils::toLower(entry.name));
|
||||
}
|
||||
|
||||
std::vector<std::size_t> indices(entries.size());
|
||||
@@ -178,12 +166,3 @@ std::string DirectoryScanner::normalizeExtension(std::string_view extension) {
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string DirectoryScanner::lower(std::string_view text) {
|
||||
std::string out;
|
||||
out.reserve(text.size());
|
||||
for (char ch : text) {
|
||||
out.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(ch))));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -38,5 +38,4 @@ private:
|
||||
const std::vector<std::string>& extensions);
|
||||
[[nodiscard]] static bool isHiddenName(std::string_view name);
|
||||
[[nodiscard]] static std::string normalizeExtension(std::string_view extension);
|
||||
[[nodiscard]] static std::string lower(std::string_view text);
|
||||
};
|
||||
|
||||
@@ -207,19 +207,6 @@ namespace {
|
||||
return out;
|
||||
}
|
||||
|
||||
[[maybe_unused]] std::string joinStrings(const std::vector<std::string>& values) {
|
||||
std::string out;
|
||||
bool first = true;
|
||||
for (const auto& value : values) {
|
||||
if (!first) {
|
||||
out += ", ";
|
||||
}
|
||||
first = false;
|
||||
out += value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool hasStrongNowPlayingMetadata(const MprisPlayerInfo& info) {
|
||||
// Track IDs/source URLs can exist during transient "loading" states where the
|
||||
// user-visible metadata is still placeholder-only (e.g. app identity + logo).
|
||||
|
||||
@@ -132,11 +132,6 @@ namespace {
|
||||
return std::string{s.substr(0, len)};
|
||||
}
|
||||
|
||||
bool isBlankText(std::string_view text) {
|
||||
return text.empty() ||
|
||||
std::all_of(text.begin(), text.end(), [](unsigned char ch) { return std::isspace(ch) != 0; });
|
||||
}
|
||||
|
||||
std::vector<std::string> sanitize_actions(const std::vector<std::string>& actions) {
|
||||
std::vector<std::string> sanitized;
|
||||
sanitized.reserve(actions.size() - (actions.size() % 2));
|
||||
@@ -149,7 +144,7 @@ namespace {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isBlankText(label)) {
|
||||
if (StringUtils::isBlank(label)) {
|
||||
label = i18n::tr("notifications.actions.fallback");
|
||||
}
|
||||
|
||||
|
||||
@@ -40,20 +40,6 @@ namespace {
|
||||
|
||||
bool looks_like_dbus_name(std::string_view value) { return !value.empty() && value != "__path_only__"; }
|
||||
|
||||
std::string trim(std::string value) {
|
||||
while (!value.empty() && std::isspace(static_cast<unsigned char>(value.back())) != 0) {
|
||||
value.pop_back();
|
||||
}
|
||||
std::size_t first = 0;
|
||||
while (first < value.size() && std::isspace(static_cast<unsigned char>(value[first])) != 0) {
|
||||
++first;
|
||||
}
|
||||
if (first > 0) {
|
||||
value.erase(0, first);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string processNameForPid(std::uint32_t pid) {
|
||||
if (pid == 0) {
|
||||
return {};
|
||||
@@ -69,7 +55,7 @@ namespace {
|
||||
std::ifstream comm(procDir / "comm");
|
||||
std::string name;
|
||||
if (std::getline(comm, name)) {
|
||||
return trim(std::move(name));
|
||||
return StringUtils::trim(name);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
+3
-10
@@ -1,23 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace noctalia::ipc {
|
||||
|
||||
inline std::vector<std::string> splitWords(std::string_view text) {
|
||||
std::vector<std::string> words;
|
||||
std::istringstream stream{std::string(text)};
|
||||
std::string word;
|
||||
while (stream >> word) {
|
||||
words.push_back(std::move(word));
|
||||
}
|
||||
return words;
|
||||
}
|
||||
inline std::vector<std::string> splitWords(std::string_view text) { return StringUtils::splitWhitespace(text); }
|
||||
|
||||
inline std::optional<float> parseNormalizedOrPercent(std::string_view token, float maxPercent = 100.0f) {
|
||||
std::string value(token);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "util/file_utils.h"
|
||||
#include "util/fuzzy_match.h"
|
||||
#include "util/string_utils.h"
|
||||
#include "wayland/wayland_connection.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -20,13 +21,6 @@ namespace {
|
||||
constexpr std::size_t kMaxSearchResults = 50;
|
||||
constexpr std::string_view kDefaultAppIcon = "application-x-executable";
|
||||
|
||||
std::string toLower(std::string_view s) {
|
||||
std::string result(s);
|
||||
std::transform(result.begin(), result.end(), result.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return result;
|
||||
}
|
||||
|
||||
double scoreEntry(std::string_view pattern, const DesktopEntry& entry) {
|
||||
if (pattern.empty()) {
|
||||
return 0.0;
|
||||
@@ -288,7 +282,7 @@ void AppProvider::refreshEntriesIfNeeded() const {
|
||||
|
||||
std::vector<LauncherResult> AppProvider::query(std::string_view text) const {
|
||||
refreshEntriesIfNeeded();
|
||||
const std::string normalizedText = toLower(text);
|
||||
const std::string normalizedText = StringUtils::toLower(text);
|
||||
const std::string_view pattern = normalizedText;
|
||||
|
||||
auto buildResult = [&](const DesktopEntry& entry, double s) {
|
||||
|
||||
@@ -10,23 +10,12 @@
|
||||
#include "ui/controls/label.h"
|
||||
#include "ui/palette.h"
|
||||
#include "ui/style.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <string_view>
|
||||
|
||||
namespace {
|
||||
|
||||
std::string toLower(std::string_view value) {
|
||||
std::string out(value);
|
||||
std::transform(out.begin(), out.end(), out.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ActiveWindowWidget::ActiveWindowWidget(CompositorPlatform& platform, float maxWidth, float minWidth, float iconSize,
|
||||
ActiveWindowTitleScrollMode titleScrollMode)
|
||||
: m_platform(platform), m_maxWidth(maxWidth), m_minWidth(minWidth), m_iconSize(iconSize),
|
||||
@@ -212,7 +201,7 @@ std::string ActiveWindowWidget::resolveIconPath(const std::string& appId) {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string appIdLower = toLower(appId);
|
||||
const std::string appIdLower = StringUtils::toLower(appId);
|
||||
if (auto it = m_appIcons.find(appIdLower); it != m_appIcons.end()) {
|
||||
const auto path = resolveByName(it->second);
|
||||
if (!path.empty()) {
|
||||
@@ -240,7 +229,7 @@ void ActiveWindowWidget::buildDesktopIconIndex() {
|
||||
return;
|
||||
}
|
||||
m_appIcons.try_emplace(std::string{key}, icon);
|
||||
m_appIcons.try_emplace(toLower(key), icon);
|
||||
m_appIcons.try_emplace(StringUtils::toLower(key), icon);
|
||||
};
|
||||
|
||||
const auto& entries = desktopEntries();
|
||||
|
||||
@@ -8,14 +8,15 @@
|
||||
#include "render/scene/node.h"
|
||||
#include "render/text/glyph_registry.h"
|
||||
#include "shell/panel/panel_manager.h"
|
||||
#include "shell/tray/tray_identifier.h"
|
||||
#include "ui/controls/flex.h"
|
||||
#include "ui/controls/glyph.h"
|
||||
#include "ui/controls/image.h"
|
||||
#include "ui/palette.h"
|
||||
#include "ui/style.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <linux/input-event-codes.h>
|
||||
@@ -28,106 +29,7 @@ namespace {
|
||||
|
||||
constexpr Logger kLog("tray");
|
||||
|
||||
std::string toLower(std::string_view value) {
|
||||
std::string out(value);
|
||||
std::transform(out.begin(), out.end(), out.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> identifierVariants(std::string_view value) {
|
||||
std::vector<std::string> out;
|
||||
if (value.empty()) {
|
||||
return out;
|
||||
}
|
||||
|
||||
auto pushUnique = [&out](std::string candidate) {
|
||||
if (candidate.empty()) {
|
||||
return;
|
||||
}
|
||||
if (std::ranges::find(out, candidate) == out.end()) {
|
||||
out.push_back(std::move(candidate));
|
||||
}
|
||||
};
|
||||
|
||||
std::string base(value);
|
||||
pushUnique(base);
|
||||
pushUnique(toLower(base));
|
||||
|
||||
if (const auto slash = base.find_last_of('/'); slash != std::string::npos && slash + 1 < base.size()) {
|
||||
base = base.substr(slash + 1);
|
||||
pushUnique(base);
|
||||
pushUnique(toLower(base));
|
||||
}
|
||||
|
||||
std::string dashed = base;
|
||||
std::replace(dashed.begin(), dashed.end(), '_', '-');
|
||||
pushUnique(dashed);
|
||||
pushUnique(toLower(dashed));
|
||||
|
||||
std::string underscored = base;
|
||||
std::replace(underscored.begin(), underscored.end(), '-', '_');
|
||||
pushUnique(underscored);
|
||||
pushUnique(toLower(underscored));
|
||||
|
||||
auto pushReducedForms = [&pushUnique](std::string candidate) {
|
||||
if (candidate.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pushUnique(candidate);
|
||||
pushUnique(toLower(candidate));
|
||||
|
||||
bool changed = true;
|
||||
while (changed && !candidate.empty()) {
|
||||
changed = false;
|
||||
|
||||
for (const auto& suffix : {"_client", "-client", ".desktop", "_indicator", "-indicator", "_tray", "-tray",
|
||||
"_status", "-status", "_panel", "-panel"}) {
|
||||
if (candidate.size() > std::char_traits<char>::length(suffix) && candidate.ends_with(suffix)) {
|
||||
candidate = candidate.substr(0, candidate.size() - std::char_traits<char>::length(suffix));
|
||||
pushUnique(candidate);
|
||||
pushUnique(toLower(candidate));
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed || candidate.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto separator = candidate.find_last_of("-_");
|
||||
if (separator != std::string::npos && separator + 1 < candidate.size()) {
|
||||
const std::string tail = candidate.substr(separator + 1);
|
||||
const bool numericTail = std::ranges::all_of(tail, [](unsigned char c) { return std::isdigit(c) != 0; });
|
||||
if (numericTail) {
|
||||
candidate = candidate.substr(0, separator);
|
||||
pushUnique(candidate);
|
||||
pushUnique(toLower(candidate));
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& suffix : {"-linux", "_linux"}) {
|
||||
if (candidate.size() > std::char_traits<char>::length(suffix) && candidate.ends_with(suffix)) {
|
||||
candidate = candidate.substr(0, candidate.size() - std::char_traits<char>::length(suffix));
|
||||
pushUnique(candidate);
|
||||
pushUnique(toLower(candidate));
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto& candidate : std::vector<std::string>{base, dashed, underscored}) {
|
||||
pushReducedForms(candidate);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
using tray::identifierVariants;
|
||||
|
||||
void addIconAlias(std::unordered_map<std::string, std::string>& index, std::string_view key, std::string_view icon) {
|
||||
if (key.empty() || icon.empty()) {
|
||||
@@ -227,7 +129,7 @@ std::string TrayWidget::resolveFromTrayThemePath(std::string_view themePath, std
|
||||
}
|
||||
|
||||
const fs::path path = it->path();
|
||||
const auto extension = toLower(path.extension().string());
|
||||
const auto extension = StringUtils::toLower(path.extension().string());
|
||||
if (extension != ".svg" && extension != ".png") {
|
||||
continue;
|
||||
}
|
||||
@@ -570,7 +472,7 @@ void TrayWidget::rebuild(Renderer& renderer) {
|
||||
if (const auto it = m_appIcons.find(overlayName); it != m_appIcons.end()) {
|
||||
return m_iconResolver.resolve(it->second);
|
||||
}
|
||||
const std::string lower = toLower(overlayName);
|
||||
const std::string lower = StringUtils::toLower(overlayName);
|
||||
if (const auto it = m_appIcons.find(lower); it != m_appIcons.end()) {
|
||||
return m_iconResolver.resolve(it->second);
|
||||
}
|
||||
@@ -803,7 +705,7 @@ std::string TrayWidget::resolveIconPath(const TrayItemInfo& item) {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string lower = toLower(name);
|
||||
const std::string lower = StringUtils::toLower(name);
|
||||
if (const auto it = m_appIcons.find(lower); it != m_appIcons.end()) {
|
||||
if (const auto mapped = m_iconResolver.resolve(it->second); !mapped.empty()) {
|
||||
return mapped;
|
||||
@@ -817,7 +719,7 @@ std::string TrayWidget::resolveIconPath(const TrayItemInfo& item) {
|
||||
return mapped;
|
||||
}
|
||||
}
|
||||
const std::string tailLower = toLower(tail);
|
||||
const std::string tailLower = StringUtils::toLower(tail);
|
||||
if (const auto it = m_appIcons.find(tailLower); it != m_appIcons.end()) {
|
||||
if (const auto mapped = m_iconResolver.resolve(it->second); !mapped.empty()) {
|
||||
return mapped;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ui/controls/virtual_grid_view.h"
|
||||
#include "ui/palette.h"
|
||||
#include "ui/style.h"
|
||||
#include "util/string_utils.h"
|
||||
#include "wayland/clipboard_service.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -47,30 +48,6 @@ namespace {
|
||||
constexpr auto kFilterDebounceInterval = std::chrono::milliseconds(120);
|
||||
constexpr Logger kLog("clipboard");
|
||||
|
||||
std::string trim(std::string_view text) {
|
||||
const auto first = text.find_first_not_of(" \t\r\n");
|
||||
if (first == std::string_view::npos) {
|
||||
return {};
|
||||
}
|
||||
const auto last = text.find_last_not_of(" \t\r\n");
|
||||
return std::string(text.substr(first, last - first + 1));
|
||||
}
|
||||
|
||||
std::string shellQuote(std::string_view text) {
|
||||
std::string quoted;
|
||||
quoted.reserve(text.size() + 2);
|
||||
quoted.push_back('\'');
|
||||
for (char ch : text) {
|
||||
if (ch == '\'') {
|
||||
quoted += "'\\''";
|
||||
} else {
|
||||
quoted.push_back(ch);
|
||||
}
|
||||
}
|
||||
quoted.push_back('\'');
|
||||
return quoted;
|
||||
}
|
||||
|
||||
void replaceAll(std::string& text, std::string_view needle, std::string_view replacement) {
|
||||
if (needle.empty()) {
|
||||
return;
|
||||
@@ -86,7 +63,7 @@ namespace {
|
||||
std::string buildImageActionCommand(std::string command, std::string_view imagePath) {
|
||||
const bool hasPathPlaceholder = command.find("{path}") != std::string::npos;
|
||||
const bool hasStdinPlaceholder = command.find("{stdin}") != std::string::npos;
|
||||
const std::string quotedPath = shellQuote(imagePath);
|
||||
const std::string quotedPath = StringUtils::shellQuote(imagePath);
|
||||
|
||||
if (hasPathPlaceholder) {
|
||||
replaceAll(command, "{path}", quotedPath);
|
||||
@@ -866,7 +843,7 @@ void ClipboardPanel::updatePreviewActions() {
|
||||
|
||||
bool showImageAction = false;
|
||||
if (m_clipboard != nullptr && m_config != nullptr &&
|
||||
!trim(m_config->config().shell.clipboardImageActionCommand).empty()) {
|
||||
!StringUtils::trim(m_config->config().shell.clipboardImageActionCommand).empty()) {
|
||||
const std::size_t historyIndex = selectedHistoryIndex();
|
||||
const auto& history = m_clipboard->history();
|
||||
showImageAction = historyIndex != static_cast<std::size_t>(-1) && historyIndex < history.size() &&
|
||||
@@ -1113,7 +1090,7 @@ void ClipboardPanel::runImageAction() {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string configuredCommand = trim(m_config->config().shell.clipboardImageActionCommand);
|
||||
const std::string configuredCommand = StringUtils::trim(m_config->config().shell.clipboardImageActionCommand);
|
||||
if (configuredCommand.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#include "ui/controls/scroll_view.h"
|
||||
#include "ui/controls/slider.h"
|
||||
#include "ui/palette.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
@@ -230,29 +230,7 @@ namespace {
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string trimAsciiWhitespaceCopy(std::string_view s) {
|
||||
std::size_t i = 0;
|
||||
std::size_t j = s.size();
|
||||
while (i < j && std::isspace(static_cast<unsigned char>(s[i])) != 0) {
|
||||
++i;
|
||||
}
|
||||
while (j > i && std::isspace(static_cast<unsigned char>(s[j - 1])) != 0) {
|
||||
--j;
|
||||
}
|
||||
return std::string(s.substr(i, j - i));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isBlankSearchKey(std::string_view s) {
|
||||
if (s.empty()) {
|
||||
return true;
|
||||
}
|
||||
for (unsigned char c : s) {
|
||||
if (std::isspace(c) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[[nodiscard]] bool isBlankSearchKey(std::string_view s) { return StringUtils::isBlank(s); }
|
||||
|
||||
bool isDesktopTokenDelimiter(unsigned char c) { return c == '-' || c == '_' || c == '.' || std::isspace(c) != 0; }
|
||||
|
||||
@@ -436,7 +414,7 @@ namespace {
|
||||
}
|
||||
|
||||
const DesktopEntry* findDesktopEntryByTerm(std::string_view term) {
|
||||
const std::string trimmed = trimAsciiWhitespaceCopy(term);
|
||||
const std::string trimmed = StringUtils::trim(term);
|
||||
if (trimmed.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -460,7 +438,7 @@ namespace {
|
||||
|
||||
DesktopEntryMatch lookupDesktopEntryForProgramStream(const AudioNode& node, std::string_view resolvedBeforeDesktop) {
|
||||
DesktopEntryMatch out;
|
||||
const std::string binary = lowerIdentifier(trimAsciiWhitespaceCopy(node.applicationBinary));
|
||||
const std::string binary = lowerIdentifier(StringUtils::trim(node.applicationBinary));
|
||||
// Wine/Proton streams report wine64-preloader etc.; matching desktop entries by that binary (or
|
||||
// the shared Icon=wine) incorrectly picks unrelated apps (e.g. Protontricks) before app/node name.
|
||||
if (!binary.empty() && !looksLikeRuntimeLauncher(node.applicationBinary)) {
|
||||
@@ -471,7 +449,7 @@ namespace {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
const std::string appId = lowerIdentifier(trimAsciiWhitespaceCopy(node.applicationId));
|
||||
const std::string appId = lowerIdentifier(StringUtils::trim(node.applicationId));
|
||||
if (!appId.empty()) {
|
||||
if (const DesktopEntry* entry = findDesktopEntryByTerm(appId)) {
|
||||
out.entry = entry;
|
||||
@@ -480,7 +458,7 @@ namespace {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
const std::string appName = lowerIdentifier(trimAsciiWhitespaceCopy(node.applicationName));
|
||||
const std::string appName = lowerIdentifier(StringUtils::trim(node.applicationName));
|
||||
if (!appName.empty() && !isGenericAudioLabel(appName) && !looksLikeRuntimeLauncher(appName)) {
|
||||
if (const DesktopEntry* entry = findDesktopEntryByTerm(appName)) {
|
||||
out.entry = entry;
|
||||
@@ -489,7 +467,7 @@ namespace {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
const std::string resolved = lowerIdentifier(trimAsciiWhitespaceCopy(resolvedBeforeDesktop));
|
||||
const std::string resolved = lowerIdentifier(StringUtils::trim(resolvedBeforeDesktop));
|
||||
if (!resolved.empty() && !isGenericAudioLabel(resolved) && !looksLikeRuntimeLauncher(resolved)) {
|
||||
if (const DesktopEntry* entry = findDesktopEntryByTerm(resolved)) {
|
||||
out.entry = entry;
|
||||
@@ -498,7 +476,7 @@ namespace {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
const std::string nodeName = lowerIdentifier(trimAsciiWhitespaceCopy(node.name));
|
||||
const std::string nodeName = lowerIdentifier(StringUtils::trim(node.name));
|
||||
if (!nodeName.empty()) {
|
||||
if (const DesktopEntry* entry = findDesktopEntryByTerm(nodeName)) {
|
||||
out.entry = entry;
|
||||
|
||||
@@ -171,11 +171,6 @@ namespace {
|
||||
localY < closeTop + kCloseButtonSize;
|
||||
}
|
||||
|
||||
bool isBlankText(std::string_view text) {
|
||||
return text.empty() ||
|
||||
std::all_of(text.begin(), text.end(), [](unsigned char ch) { return std::isspace(ch) != 0; });
|
||||
}
|
||||
|
||||
float measureActionsFromPairs(RenderContext& rc, const std::vector<std::string>& actions) {
|
||||
if (actions.empty()) {
|
||||
return 0.0f;
|
||||
@@ -190,7 +185,7 @@ namespace {
|
||||
for (std::size_t i = 0; i + 1 < actions.size() && actionCount < kMaxActionButtons; i += 2) {
|
||||
const std::string& actionKey = actions[i];
|
||||
std::string actionLabel = actions[i + 1];
|
||||
if (isBlankText(actionLabel)) {
|
||||
if (StringUtils::isBlank(actionLabel)) {
|
||||
actionLabel = fallbackActionLabel();
|
||||
}
|
||||
if (actionKey.empty()) {
|
||||
@@ -237,7 +232,7 @@ namespace {
|
||||
|
||||
ToastGeometry out;
|
||||
|
||||
if (isBlankText(displayBody)) {
|
||||
if (StringUtils::isBlank(displayBody)) {
|
||||
Label summaryProbe;
|
||||
summaryProbe.setFontSize(kSummaryFontSize);
|
||||
summaryProbe.setBold(true);
|
||||
@@ -490,7 +485,7 @@ void NotificationToast::onNotificationEvent(const Notification& n, NotificationE
|
||||
cs.bodyLabel->setMaxLines(std::max(1, bodyLines));
|
||||
cs.bodyLabel->setText(bodyLines > 0 ? displayBody : "");
|
||||
cs.bodyLabel->measure(*m_renderContext);
|
||||
cs.bodyLabel->setVisible(bodyLines > 0 && !isBlankText(displayBody));
|
||||
cs.bodyLabel->setVisible(bodyLines > 0 && !StringUtils::isBlank(displayBody));
|
||||
cs.bodyLabel->setPosition(notificationTextStartX(), bodyTopForSummary(summaryH));
|
||||
clampBodyLabelHeight(*cs.bodyLabel, bodyHeight);
|
||||
}
|
||||
@@ -1638,7 +1633,7 @@ InputArea* NotificationToast::buildCard(const PopupEntry& entry, Node** outCardC
|
||||
for (std::size_t i = 0; i + 1 < entry.actions.size() && actionCount < kMaxActionButtons; i += 2) {
|
||||
const std::string actionKey = entry.actions[i];
|
||||
std::string actionLabel = entry.actions[i + 1];
|
||||
if (isBlankText(actionLabel)) {
|
||||
if (StringUtils::isBlank(actionLabel)) {
|
||||
actionLabel = fallbackActionLabel();
|
||||
}
|
||||
if (actionKey.empty()) {
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
#include "shell/control_center/shortcut_registry.h"
|
||||
#include "theme/builtin_palettes.h"
|
||||
#include "theme/builtin_templates.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
@@ -145,13 +145,6 @@ namespace settings {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string lower(std::string_view value) {
|
||||
std::string out(value);
|
||||
std::transform(out.begin(), out.end(), out.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return out;
|
||||
}
|
||||
|
||||
SettingEntry makeEntry(std::string section, std::string group, std::string title, std::string subtitle,
|
||||
std::vector<std::string> path, SettingControl control, std::string tags = {},
|
||||
bool advanced = false) {
|
||||
@@ -167,7 +160,7 @@ namespace settings {
|
||||
.path = std::move(path),
|
||||
.control = std::move(control),
|
||||
.advanced = advanced,
|
||||
.searchText = lower(searchText),
|
||||
.searchText = StringUtils::toLower(searchText),
|
||||
.visibleWhen = std::nullopt,
|
||||
};
|
||||
}
|
||||
@@ -201,7 +194,7 @@ namespace settings {
|
||||
return names;
|
||||
}
|
||||
|
||||
std::string normalizedSettingQuery(std::string_view query) { return lower(query); }
|
||||
std::string normalizedSettingQuery(std::string_view query) { return StringUtils::toLower(query); }
|
||||
|
||||
bool matchesNormalizedSettingQuery(const SettingEntry& entry, std::string_view normalizedQuery) {
|
||||
if (normalizedQuery.empty()) {
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
#include "ui/controls/toggle.h"
|
||||
#include "ui/palette.h"
|
||||
#include "ui/style.h"
|
||||
#include "util/string_utils.h"
|
||||
#include "wayland/wayland_connection.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
@@ -51,16 +51,10 @@ namespace settings {
|
||||
return label;
|
||||
}
|
||||
|
||||
std::string toLowerAscii(std::string text) {
|
||||
std::transform(text.begin(), text.end(), text.begin(),
|
||||
[](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
|
||||
return text;
|
||||
}
|
||||
|
||||
void sortSearchOptions(std::vector<SearchPickerOption>& options) {
|
||||
std::sort(options.begin(), options.end(), [](const SearchPickerOption& a, const SearchPickerOption& b) {
|
||||
const std::string aLabel = toLowerAscii(a.label);
|
||||
const std::string bLabel = toLowerAscii(b.label);
|
||||
const std::string aLabel = StringUtils::toLower(a.label);
|
||||
const std::string bLabel = StringUtils::toLower(b.label);
|
||||
if (aLabel == bLabel) {
|
||||
return a.value < b.value;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace tray {
|
||||
|
||||
inline std::vector<std::string> identifierVariants(std::string_view value) {
|
||||
std::vector<std::string> out;
|
||||
if (value.empty()) {
|
||||
return out;
|
||||
}
|
||||
|
||||
auto pushUnique = [&out](std::string candidate) {
|
||||
if (candidate.empty()) {
|
||||
return;
|
||||
}
|
||||
if (std::ranges::find(out, candidate) == out.end()) {
|
||||
out.push_back(std::move(candidate));
|
||||
}
|
||||
};
|
||||
|
||||
std::string base(value);
|
||||
pushUnique(base);
|
||||
pushUnique(StringUtils::toLower(base));
|
||||
|
||||
if (const auto slash = base.find_last_of('/'); slash != std::string::npos && slash + 1 < base.size()) {
|
||||
base = base.substr(slash + 1);
|
||||
pushUnique(base);
|
||||
pushUnique(StringUtils::toLower(base));
|
||||
}
|
||||
|
||||
std::string dashed = base;
|
||||
std::replace(dashed.begin(), dashed.end(), '_', '-');
|
||||
pushUnique(dashed);
|
||||
pushUnique(StringUtils::toLower(dashed));
|
||||
|
||||
std::string underscored = base;
|
||||
std::replace(underscored.begin(), underscored.end(), '-', '_');
|
||||
pushUnique(underscored);
|
||||
pushUnique(StringUtils::toLower(underscored));
|
||||
|
||||
auto pushReducedForms = [&pushUnique](std::string candidate) {
|
||||
if (candidate.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pushUnique(candidate);
|
||||
pushUnique(StringUtils::toLower(candidate));
|
||||
|
||||
bool changed = true;
|
||||
while (changed && !candidate.empty()) {
|
||||
changed = false;
|
||||
|
||||
for (const auto& suffix : {"_client", "-client", ".desktop", "_indicator", "-indicator", "_tray", "-tray",
|
||||
"_status", "-status", "_panel", "-panel"}) {
|
||||
if (candidate.size() > std::char_traits<char>::length(suffix) && candidate.ends_with(suffix)) {
|
||||
candidate = candidate.substr(0, candidate.size() - std::char_traits<char>::length(suffix));
|
||||
pushUnique(candidate);
|
||||
pushUnique(StringUtils::toLower(candidate));
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed || candidate.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto separator = candidate.find_last_of("-_");
|
||||
if (separator != std::string::npos && separator + 1 < candidate.size()) {
|
||||
const std::string tail = candidate.substr(separator + 1);
|
||||
const bool numericTail = std::ranges::all_of(tail, [](unsigned char c) { return std::isdigit(c) != 0; });
|
||||
if (numericTail) {
|
||||
candidate = candidate.substr(0, separator);
|
||||
pushUnique(candidate);
|
||||
pushUnique(StringUtils::toLower(candidate));
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& suffix : {"-linux", "_linux"}) {
|
||||
if (candidate.size() > std::char_traits<char>::length(suffix) && candidate.ends_with(suffix)) {
|
||||
candidate = candidate.substr(0, candidate.size() - std::char_traits<char>::length(suffix));
|
||||
pushUnique(candidate);
|
||||
pushUnique(StringUtils::toLower(candidate));
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto& candidate : std::vector<std::string>{base, dashed, underscored}) {
|
||||
pushReducedForms(candidate);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace tray
|
||||
@@ -8,15 +8,16 @@
|
||||
#include "i18n/i18n.h"
|
||||
#include "render/render_context.h"
|
||||
#include "shell/panel/panel_manager.h"
|
||||
#include "shell/tray/tray_identifier.h"
|
||||
#include "ui/controls/context_menu.h"
|
||||
#include "ui/style.h"
|
||||
#include "util/string_utils.h"
|
||||
#include "wayland/layer_surface.h"
|
||||
#include "wayland/wayland_connection.h"
|
||||
#include "wayland/wayland_seat.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
@@ -81,55 +82,13 @@ namespace {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string toLower(std::string_view value) {
|
||||
std::string out(value);
|
||||
std::transform(out.begin(), out.end(), out.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> identifierVariants(std::string_view value) {
|
||||
std::vector<std::string> out;
|
||||
if (value.empty()) {
|
||||
return out;
|
||||
}
|
||||
auto pushUnique = [&out](std::string candidate) {
|
||||
if (candidate.empty()) {
|
||||
return;
|
||||
}
|
||||
if (std::ranges::find(out, candidate) == out.end()) {
|
||||
out.push_back(std::move(candidate));
|
||||
}
|
||||
};
|
||||
|
||||
std::string base(value);
|
||||
pushUnique(base);
|
||||
pushUnique(toLower(base));
|
||||
|
||||
if (const auto slash = base.find_last_of('/'); slash != std::string::npos && slash + 1 < base.size()) {
|
||||
base = base.substr(slash + 1);
|
||||
pushUnique(base);
|
||||
pushUnique(toLower(base));
|
||||
}
|
||||
|
||||
std::string dashed = base;
|
||||
std::replace(dashed.begin(), dashed.end(), '_', '-');
|
||||
pushUnique(dashed);
|
||||
pushUnique(toLower(dashed));
|
||||
|
||||
std::string underscored = base;
|
||||
std::replace(underscored.begin(), underscored.end(), '-', '_');
|
||||
pushUnique(underscored);
|
||||
pushUnique(toLower(underscored));
|
||||
|
||||
return out;
|
||||
}
|
||||
using tray::identifierVariants;
|
||||
|
||||
bool tokenMatchesItem(std::string_view token, const TrayItemInfo& item) {
|
||||
if (token.empty()) {
|
||||
return false;
|
||||
}
|
||||
const auto normalizedToken = toLower(token);
|
||||
const auto normalizedToken = StringUtils::toLower(token);
|
||||
|
||||
std::vector<std::string> candidates;
|
||||
auto appendVariants = [&candidates](std::string_view text) {
|
||||
@@ -157,7 +116,7 @@ namespace {
|
||||
if (value.empty()) {
|
||||
return true;
|
||||
}
|
||||
const auto lower = toLower(value);
|
||||
const auto lower = StringUtils::toLower(value);
|
||||
return lower.find("status_icon") != std::string::npos || lower.find("statusnotifieritem") != std::string::npos ||
|
||||
lower.find("statusnotifier") != std::string::npos || lower.find("status-notifier") != std::string::npos ||
|
||||
lower.find("status notifier") != std::string::npos;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "dbus/system_bus.h"
|
||||
#include "ipc/ipc_arg_parse.h"
|
||||
#include "ipc/ipc_service.h"
|
||||
#include "util/string_utils.h"
|
||||
#include "wayland/wayland_connection.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -132,25 +133,6 @@ namespace {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string trim(std::string_view input) {
|
||||
std::size_t start = 0;
|
||||
while (start < input.size() && std::isspace(static_cast<unsigned char>(input[start])) != 0) {
|
||||
++start;
|
||||
}
|
||||
std::size_t end = input.size();
|
||||
while (end > start && std::isspace(static_cast<unsigned char>(input[end - 1])) != 0) {
|
||||
--end;
|
||||
}
|
||||
return std::string(input.substr(start, end - start));
|
||||
}
|
||||
|
||||
std::string toLower(std::string_view input) {
|
||||
std::string out(input);
|
||||
std::transform(out.begin(), out.end(), out.begin(),
|
||||
[](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
|
||||
return out;
|
||||
}
|
||||
|
||||
int readSysfsInt(const std::string& path) {
|
||||
std::ifstream file(path);
|
||||
int value = -1;
|
||||
@@ -337,7 +319,7 @@ namespace {
|
||||
}
|
||||
|
||||
std::string normalizeConnectorName(std::string_view raw) {
|
||||
std::string connector = trim(raw);
|
||||
std::string connector = StringUtils::trim(raw);
|
||||
if (connector.starts_with("card")) {
|
||||
const auto dash = connector.find('-');
|
||||
if (dash != std::string::npos) {
|
||||
@@ -352,7 +334,7 @@ namespace {
|
||||
while (start <= output.size()) {
|
||||
const std::size_t end = output.find('\n', start);
|
||||
const std::string line = output.substr(start, end == std::string::npos ? output.size() - start : end - start);
|
||||
const std::string lower = toLower(line);
|
||||
const std::string lower = StringUtils::toLower(line);
|
||||
const std::size_t currentPos = lower.find("current value");
|
||||
const std::size_t maxPos = lower.find("max value");
|
||||
if (currentPos == std::string::npos || maxPos == std::string::npos || maxPos <= currentPos) {
|
||||
@@ -520,7 +502,8 @@ namespace {
|
||||
return {};
|
||||
}
|
||||
if (detectResult.exitCode != 0) {
|
||||
kLog.warn("ddcutil detect failed with exit code {}: {}", detectResult.exitCode, trim(detectResult.output));
|
||||
kLog.warn("ddcutil detect failed with exit code {}: {}", detectResult.exitCode,
|
||||
StringUtils::trim(detectResult.output));
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -536,7 +519,8 @@ namespace {
|
||||
current.currentRaw = brightness->first;
|
||||
current.maxRaw = brightness->second;
|
||||
} else {
|
||||
kLog.warn("ddcutil: skipping bus {} because brightness query failed: {}", current.bus, trim(getvcpDetail));
|
||||
kLog.warn("ddcutil: skipping bus {} because brightness query failed: {}", current.bus,
|
||||
StringUtils::trim(getvcpDetail));
|
||||
}
|
||||
}
|
||||
if (current.currentRaw >= 0 && current.maxRaw > 0) {
|
||||
@@ -549,7 +533,7 @@ namespace {
|
||||
std::size_t start = 0;
|
||||
while (start <= detectResult.output.size()) {
|
||||
const std::size_t end = detectResult.output.find('\n', start);
|
||||
const std::string line = trim(detectResult.output.substr(
|
||||
const std::string line = StringUtils::trim(detectResult.output.substr(
|
||||
start, end == std::string::npos ? detectResult.output.size() - start : end - start));
|
||||
if (line.starts_with("Display ")) {
|
||||
flushCurrent();
|
||||
@@ -566,9 +550,9 @@ namespace {
|
||||
} else if (line.starts_with("DRM_connector:")) {
|
||||
current.connectorName = normalizeConnectorName(line.substr(std::strlen("DRM_connector:")));
|
||||
} else if (line.starts_with("Monitor:")) {
|
||||
current.label = trim(line.substr(std::strlen("Monitor:")));
|
||||
current.label = StringUtils::trim(line.substr(std::strlen("Monitor:")));
|
||||
} else if (line.starts_with("Model:") && current.label.empty()) {
|
||||
current.label = trim(line.substr(std::strlen("Model:")));
|
||||
current.label = StringUtils::trim(line.substr(std::strlen("Model:")));
|
||||
}
|
||||
|
||||
if (end == std::string::npos) {
|
||||
@@ -1232,7 +1216,7 @@ struct BrightnessService::Impl {
|
||||
display->failureCount, kDdcFailureCooldown.count());
|
||||
} else {
|
||||
kLog.warn("ddcutil {} failed for '{}': {}", completion.type == WorkerCompletion::Type::Set ? "write" : "refresh",
|
||||
display->pub.id, trim(completion.detail));
|
||||
display->pub.id, StringUtils::trim(completion.detail));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "system/desktop_entry.h"
|
||||
|
||||
#include "core/log.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
@@ -18,15 +19,8 @@ namespace {
|
||||
|
||||
constexpr Logger kLog("desktop_entry");
|
||||
|
||||
std::string toLower(std::string_view s) {
|
||||
std::string result(s);
|
||||
std::transform(result.begin(), result.end(), result.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return result;
|
||||
}
|
||||
|
||||
bool parseDesktopBool(std::string_view value) {
|
||||
const std::string lower = toLower(value);
|
||||
const std::string lower = StringUtils::toLower(value);
|
||||
return lower == "true" || lower == "1" || lower == "yes";
|
||||
}
|
||||
|
||||
@@ -263,13 +257,13 @@ namespace {
|
||||
}
|
||||
|
||||
// Pre-lowercase for matching
|
||||
entry.nameLower = toLower(entry.name);
|
||||
entry.genericNameLower = toLower(entry.genericName);
|
||||
entry.keywordsLower = toLower(entry.keywords);
|
||||
entry.categoriesLower = toLower(entry.categories);
|
||||
entry.startupWmClassLower = toLower(entry.startupWmClass);
|
||||
entry.idLower = toLower(entry.id);
|
||||
entry.execLower = toLower(entry.exec);
|
||||
entry.nameLower = StringUtils::toLower(entry.name);
|
||||
entry.genericNameLower = StringUtils::toLower(entry.genericName);
|
||||
entry.keywordsLower = StringUtils::toLower(entry.keywords);
|
||||
entry.categoriesLower = StringUtils::toLower(entry.categories);
|
||||
entry.startupWmClassLower = StringUtils::toLower(entry.startupWmClass);
|
||||
entry.idLower = StringUtils::toLower(entry.id);
|
||||
entry.execLower = StringUtils::toLower(entry.exec);
|
||||
|
||||
// Build actions in the declared order.
|
||||
for (const auto& id : actionOrder) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "system/distro_info.h"
|
||||
|
||||
#include "i18n/i18n.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
@@ -21,44 +22,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
std::string trim(std::string_view value) {
|
||||
std::size_t start = 0;
|
||||
while (start < value.size() && std::isspace(static_cast<unsigned char>(value[start])) != 0) {
|
||||
++start;
|
||||
}
|
||||
|
||||
std::size_t end = value.size();
|
||||
while (end > start && std::isspace(static_cast<unsigned char>(value[end - 1])) != 0) {
|
||||
--end;
|
||||
}
|
||||
|
||||
return std::string(value.substr(start, end - start));
|
||||
}
|
||||
|
||||
std::string unquote(std::string value) {
|
||||
if (value.size() >= 2 &&
|
||||
((value.front() == '"' && value.back() == '"') || (value.front() == '\'' && value.back() == '\''))) {
|
||||
value = value.substr(1, value.size() - 2);
|
||||
}
|
||||
|
||||
std::string out;
|
||||
out.reserve(value.size());
|
||||
bool escaping = false;
|
||||
for (char ch : value) {
|
||||
if (escaping) {
|
||||
out.push_back(ch);
|
||||
escaping = false;
|
||||
continue;
|
||||
}
|
||||
if (ch == '\\') {
|
||||
escaping = true;
|
||||
continue;
|
||||
}
|
||||
out.push_back(ch);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::optional<std::unordered_map<std::string, std::string>> parseOsRelease(const std::filesystem::path& path) {
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
@@ -68,7 +31,7 @@ namespace {
|
||||
std::unordered_map<std::string, std::string> values;
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
const auto trimmed = trim(line);
|
||||
const auto trimmed = StringUtils::trim(line);
|
||||
if (trimmed.empty() || trimmed.front() == '#') {
|
||||
continue;
|
||||
}
|
||||
@@ -79,7 +42,7 @@ namespace {
|
||||
}
|
||||
|
||||
auto key = std::string(trimmed.substr(0, eq));
|
||||
auto value = unquote(trim(std::string_view(trimmed).substr(eq + 1)));
|
||||
auto value = StringUtils::unquote(StringUtils::trim(std::string_view(trimmed).substr(eq + 1)));
|
||||
values[std::move(key)] = std::move(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "compositors/compositor_detect.h"
|
||||
#include "i18n/i18n.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
@@ -13,14 +14,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
std::string trimWhitespace(std::string s) {
|
||||
while (!s.empty() && (s.back() == ' ' || s.back() == '\t' || s.back() == '\n' || s.back() == '\r')) {
|
||||
s.pop_back();
|
||||
}
|
||||
const auto start = s.find_first_not_of(" \t");
|
||||
return start == std::string::npos ? "" : s.substr(start);
|
||||
}
|
||||
|
||||
std::string readCpuModel() {
|
||||
std::ifstream file{"/proc/cpuinfo"};
|
||||
if (!file.is_open()) {
|
||||
@@ -32,7 +25,7 @@ namespace {
|
||||
if (line.starts_with("model name")) {
|
||||
const auto colonPos = line.find(':');
|
||||
if (colonPos != std::string::npos) {
|
||||
return trimWhitespace(line.substr(colonPos + 1));
|
||||
return StringUtils::trim(line.substr(colonPos + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,7 +54,7 @@ namespace {
|
||||
if (line.starts_with(vendorId)) {
|
||||
const auto nameStart = line.find(" ");
|
||||
if (nameStart != std::string::npos) {
|
||||
vendorName = trimWhitespace(line.substr(nameStart));
|
||||
vendorName = StringUtils::trim(line.substr(nameStart));
|
||||
inVendor = true;
|
||||
}
|
||||
}
|
||||
@@ -73,11 +66,11 @@ namespace {
|
||||
}
|
||||
|
||||
if (line[0] == '\t' && (line.size() < 2 || line[1] != '\t')) {
|
||||
auto stripped = trimWhitespace(line);
|
||||
auto stripped = StringUtils::trim(line);
|
||||
if (stripped.starts_with(deviceId)) {
|
||||
const auto nameStart = stripped.find(" ");
|
||||
if (nameStart != std::string::npos) {
|
||||
auto deviceName = trimWhitespace(stripped.substr(nameStart));
|
||||
auto deviceName = StringUtils::trim(stripped.substr(nameStart));
|
||||
if (!deviceName.empty()) {
|
||||
return deviceName;
|
||||
}
|
||||
@@ -99,7 +92,7 @@ namespace {
|
||||
}
|
||||
std::string line;
|
||||
std::getline(file, line);
|
||||
return trimWhitespace(line);
|
||||
return StringUtils::trim(line);
|
||||
}
|
||||
|
||||
std::string detectGpu() {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "system/icon_resolver.h"
|
||||
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
@@ -34,17 +36,7 @@ namespace {
|
||||
return state;
|
||||
}
|
||||
|
||||
std::string trim(std::string_view value) {
|
||||
while (!value.empty() && (value.front() == '\'' || value.front() == '"' || value.front() == ' ' ||
|
||||
value.front() == '\t' || value.front() == '\r' || value.front() == '\n')) {
|
||||
value = value.substr(1);
|
||||
}
|
||||
while (!value.empty() && (value.back() == '\'' || value.back() == '"' || value.back() == ' ' ||
|
||||
value.back() == '\t' || value.back() == '\r' || value.back() == '\n')) {
|
||||
value = value.substr(0, value.size() - 1);
|
||||
}
|
||||
return std::string(value);
|
||||
}
|
||||
std::string trimAndUnquote(std::string_view value) { return StringUtils::unquote(StringUtils::trim(value)); }
|
||||
|
||||
void pushUnique(std::vector<std::string>& values, std::string value) {
|
||||
if (value.empty()) {
|
||||
@@ -61,7 +53,7 @@ namespace {
|
||||
while (start <= value.size()) {
|
||||
const auto next = value.find(separator, start);
|
||||
const auto part = next == std::string_view::npos ? value.substr(start) : value.substr(start, next - start);
|
||||
const std::string trimmed = trim(part);
|
||||
const std::string trimmed = trimAndUnquote(part);
|
||||
if (!trimmed.empty()) {
|
||||
parts.push_back(trimmed);
|
||||
}
|
||||
@@ -181,7 +173,7 @@ namespace {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string value = trim(raw);
|
||||
std::string value = trimAndUnquote(raw);
|
||||
g_free(raw);
|
||||
if (value.empty()) {
|
||||
return std::nullopt;
|
||||
@@ -217,7 +209,7 @@ namespace {
|
||||
if (eq == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
std::string value = trim(std::string_view(line.data() + eq + 1, line.size() - eq - 1));
|
||||
std::string value = trimAndUnquote(std::string_view(line.data() + eq + 1, line.size() - eq - 1));
|
||||
if (!value.empty()) {
|
||||
candidates.emplace_back(std::move(value));
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "system/system_monitor_service.h"
|
||||
|
||||
#include "core/log.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
@@ -75,16 +75,10 @@ namespace {
|
||||
return static_cast<double>(raw);
|
||||
}
|
||||
|
||||
std::string toLower(std::string value) {
|
||||
std::transform(value.begin(), value.end(), value.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return value;
|
||||
}
|
||||
|
||||
int scoreHwmonSensor(const std::string& hwmon_name, const std::string& label) {
|
||||
int score = 0;
|
||||
const std::string name = toLower(hwmon_name);
|
||||
const std::string lbl = toLower(label);
|
||||
const std::string name = StringUtils::toLower(hwmon_name);
|
||||
const std::string lbl = StringUtils::toLower(label);
|
||||
|
||||
if (name.find("coretemp") != std::string::npos || name.find("k10temp") != std::string::npos ||
|
||||
name.find("zenpower") != std::string::npos || name.find("cpu") != std::string::npos) {
|
||||
@@ -100,14 +94,14 @@ namespace {
|
||||
}
|
||||
|
||||
bool isCpuThermalZoneType(const std::string& type) {
|
||||
const std::string t = toLower(type);
|
||||
const std::string t = StringUtils::toLower(type);
|
||||
return t.find("x86_pkg_temp") != std::string::npos || t.find("cpu") != std::string::npos ||
|
||||
t.find("soc") != std::string::npos || t.find("package") != std::string::npos;
|
||||
}
|
||||
|
||||
int scoreGpuHwmonSensor(const std::string& hwmon_name, const std::string& label) {
|
||||
const std::string name = toLower(hwmon_name);
|
||||
const std::string lbl = toLower(label);
|
||||
const std::string name = StringUtils::toLower(hwmon_name);
|
||||
const std::string lbl = StringUtils::toLower(label);
|
||||
|
||||
if (name.find("nvidia") != std::string::npos) {
|
||||
return -1;
|
||||
|
||||
@@ -355,25 +355,14 @@ namespace noctalia::theme {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string replaceAll(std::string value, const std::string& from, const std::string& to) {
|
||||
if (from.empty())
|
||||
return value;
|
||||
size_t pos = 0;
|
||||
while ((pos = value.find(from, pos)) != std::string::npos) {
|
||||
value.replace(pos, from.size(), to);
|
||||
pos += to.size();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string applyReplace(const std::string& value, const std::optional<std::string>& arg) {
|
||||
if (!arg)
|
||||
return value;
|
||||
std::smatch match;
|
||||
if (std::regex_match(*arg, match, std::regex(R"REGEX("([^"]*?)"\s*,\s*"([^"]*?)")REGEX")))
|
||||
return replaceAll(value, match[1].str(), match[2].str());
|
||||
return StringUtils::replaceAll(value, match[1].str(), match[2].str());
|
||||
if (std::regex_match(*arg, match, std::regex(R"REGEX('([^']*?)'\s*,\s*'([^']*?)')REGEX")))
|
||||
return replaceAll(value, match[1].str(), match[2].str());
|
||||
return StringUtils::replaceAll(value, match[1].str(), match[2].str());
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
#include "ui/controls/virtual_grid_view.h"
|
||||
#include "ui/palette.h"
|
||||
#include "ui/style.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
@@ -37,13 +37,6 @@ namespace {
|
||||
button.setRadius(Style::radiusMd * scale);
|
||||
}
|
||||
|
||||
std::string toLowerCopy(std::string_view value) {
|
||||
std::string out(value);
|
||||
std::transform(out.begin(), out.end(), out.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class GlyphGridAdapter : public VirtualGridAdapter {
|
||||
@@ -136,7 +129,7 @@ public:
|
||||
}
|
||||
return;
|
||||
}
|
||||
const std::string needle = toLowerCopy(filter);
|
||||
const std::string needle = StringUtils::toLower(filter);
|
||||
for (std::size_t i = 0; i < m_master.size(); ++i) {
|
||||
// Names in the registry are already lowercase; no need to lower each entry.
|
||||
if (m_master[i].name.find(needle) != std::string::npos) {
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
#include "ui/dialogs/file_entry_row.h"
|
||||
#include "ui/dialogs/file_entry_tile.h"
|
||||
#include "ui/style.h"
|
||||
#include "util/string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
@@ -33,15 +33,6 @@ namespace {
|
||||
constexpr std::size_t kGridRowOverscan = 1;
|
||||
constexpr float kGridMinCellWidth = 140.0f;
|
||||
|
||||
std::string lower(std::string_view text) {
|
||||
std::string out;
|
||||
out.reserve(text.size());
|
||||
for (char ch : text) {
|
||||
out.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(ch))));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void configureDialogActionButton(Button& button, float scale) {
|
||||
button.setMinHeight(Style::controlHeight * scale);
|
||||
button.setMinWidth(92.0f * scale);
|
||||
@@ -614,11 +605,11 @@ void FileDialogView::refreshDirectory() {
|
||||
|
||||
void FileDialogView::applyFilter(bool resetScroll) {
|
||||
const std::filesystem::path preserved = selectedPath();
|
||||
const std::string query = lower(m_filterQuery);
|
||||
const std::string query = StringUtils::toLower(m_filterQuery);
|
||||
|
||||
m_visibleEntries.clear();
|
||||
for (const auto& entry : m_entries) {
|
||||
if (!query.empty() && lower(entry.name).find(query) == std::string::npos) {
|
||||
if (!query.empty() && StringUtils::toLower(entry.name).find(query) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
m_visibleEntries.push_back(entry);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace StringUtils {
|
||||
|
||||
@@ -154,4 +155,120 @@ namespace StringUtils {
|
||||
return out;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::vector<std::string> splitWhitespace(std::string_view text) {
|
||||
std::vector<std::string> result;
|
||||
std::size_t i = 0;
|
||||
while (i < text.size()) {
|
||||
while (i < text.size() && std::isspace(static_cast<unsigned char>(text[i])) != 0) {
|
||||
++i;
|
||||
}
|
||||
if (i >= text.size()) {
|
||||
break;
|
||||
}
|
||||
std::size_t start = i;
|
||||
while (i < text.size() && std::isspace(static_cast<unsigned char>(text[i])) == 0) {
|
||||
++i;
|
||||
}
|
||||
result.emplace_back(text.substr(start, i - start));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::vector<std::string_view> split(std::string_view text, char delimiter) {
|
||||
std::vector<std::string_view> result;
|
||||
std::size_t start = 0;
|
||||
while (start <= text.size()) {
|
||||
std::size_t pos = text.find(delimiter, start);
|
||||
if (pos == std::string_view::npos) {
|
||||
result.push_back(text.substr(start));
|
||||
break;
|
||||
}
|
||||
result.push_back(text.substr(start, pos - start));
|
||||
start = pos + 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string join(const std::vector<std::string>& parts, std::string_view separator) {
|
||||
std::string result;
|
||||
for (std::size_t i = 0; i < parts.size(); ++i) {
|
||||
if (i > 0) {
|
||||
result.append(separator);
|
||||
}
|
||||
result.append(parts[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string replaceAll(std::string_view input, std::string_view from, std::string_view to) {
|
||||
if (from.empty()) {
|
||||
return std::string(input);
|
||||
}
|
||||
std::string result;
|
||||
result.reserve(input.size());
|
||||
std::size_t pos = 0;
|
||||
while (pos < input.size()) {
|
||||
std::size_t found = input.find(from, pos);
|
||||
if (found == std::string_view::npos) {
|
||||
result.append(input.substr(pos));
|
||||
break;
|
||||
}
|
||||
result.append(input.substr(pos, found - pos));
|
||||
result.append(to);
|
||||
pos = found + from.size();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool isBlank(std::string_view text) {
|
||||
return text.empty() ||
|
||||
std::all_of(text.begin(), text.end(), [](unsigned char ch) { return std::isspace(ch) != 0; });
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string shellQuote(std::string_view text) {
|
||||
std::string result = "'";
|
||||
for (char ch : text) {
|
||||
if (ch == '\'') {
|
||||
result += "'\\''";
|
||||
} else {
|
||||
result += ch;
|
||||
}
|
||||
}
|
||||
result += '\'';
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string quoteDouble(std::string_view text) {
|
||||
std::string result = "\"";
|
||||
for (char ch : text) {
|
||||
if (ch == '\\' || ch == '"') {
|
||||
result += '\\';
|
||||
}
|
||||
result += ch;
|
||||
}
|
||||
result += '"';
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string unquote(std::string_view text) {
|
||||
if (text.size() < 2) {
|
||||
return std::string(text);
|
||||
}
|
||||
char front = text.front();
|
||||
char back = text.back();
|
||||
if ((front == '"' && back == '"') || (front == '\'' && back == '\'')) {
|
||||
text = text.substr(1, text.size() - 2);
|
||||
std::string result;
|
||||
result.reserve(text.size());
|
||||
for (std::size_t i = 0; i < text.size(); ++i) {
|
||||
if (text[i] == '\\' && i + 1 < text.size()) {
|
||||
++i;
|
||||
}
|
||||
result += text[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return std::string(text);
|
||||
}
|
||||
|
||||
} // namespace StringUtils
|
||||
|
||||
Reference in New Issue
Block a user