mirror of
https://github.com/geode-sdk/geode.git
synced 2025-04-24 05:14:40 -04:00
rename utils namespaces to be consistent + add file picking function +
implement it on windows via NFD + settings are pretty much finished
This commit is contained in:
parent
86f8d820d2
commit
6d2718ce09
36 changed files with 780 additions and 279 deletions
loader
include/Geode
loader
utils
src
index
internal
load
ui
internal
nodes
utils
test/dependency
|
@ -1,13 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/DefaultInclude.hpp>
|
||||
#include "../utils/container.hpp"
|
||||
#include <optional>
|
||||
#include <unordered_set>
|
||||
#include "../utils/container.hpp"
|
||||
#include "../utils/json.hpp"
|
||||
#include "../utils/Result.hpp"
|
||||
#include "../utils/JsonValidation.hpp"
|
||||
#include "../utils/convert.hpp"
|
||||
#include "../utils/platform.hpp"
|
||||
#include <regex>
|
||||
|
||||
namespace geode {
|
||||
|
@ -79,13 +80,14 @@ namespace geode {
|
|||
class IMinMax;
|
||||
template<class Class, class ValueType>
|
||||
class IOneOf;
|
||||
template<class Class>
|
||||
template<class Class, class ValueType>
|
||||
class IMatch;
|
||||
|
||||
class ICArrows;
|
||||
template<class ValueType>
|
||||
class ICSlider;
|
||||
class ICInput;
|
||||
class ICFileFilters;
|
||||
|
||||
template<class Class, class ValueType, SettingType Type>
|
||||
class GeodeSetting : public Setting {
|
||||
|
@ -110,7 +112,7 @@ namespace geode {
|
|||
obj.has("description").intoAs<std::string>(res->m_description);
|
||||
GEODE_INT_PARSE_SETTING_IMPL(obj, parseMinMax, IMinMax<ValueType>);
|
||||
GEODE_INT_PARSE_SETTING_IMPL(obj, parseOneOf, IOneOf<Class, ValueType>);
|
||||
GEODE_INT_PARSE_SETTING_IMPL(obj, parseMatch, IMatch<Class>);
|
||||
GEODE_INT_PARSE_SETTING_IMPL(obj, parseMatch, IMatch<Class, ValueType>);
|
||||
res->setValue(res->m_default);
|
||||
|
||||
if (auto controls = obj.has("control").obj()) {
|
||||
|
@ -120,6 +122,7 @@ namespace geode {
|
|||
GEODE_INT_PARSE_SETTING_IMPL(controls, parseArrows, ICArrows);
|
||||
GEODE_INT_PARSE_SETTING_IMPL(controls, parseSlider, ICSlider<ValueType>);
|
||||
GEODE_INT_PARSE_SETTING_IMPL(controls, parseInput, ICInput);
|
||||
GEODE_INT_PARSE_SETTING_IMPL(controls, parseFileFilters, ICFileFilters);
|
||||
}
|
||||
|
||||
return Ok(res);
|
||||
|
@ -152,7 +155,7 @@ namespace geode {
|
|||
if constexpr (std::is_base_of_v<IOneOf<Class, ValueType>, Class>) {
|
||||
static_cast<Class*>(this)->constrainOneOf(m_value);
|
||||
}
|
||||
if constexpr (std::is_base_of_v<IMatch<Class>, Class>) {
|
||||
if constexpr (std::is_base_of_v<IMatch<Class, ValueType>, Class>) {
|
||||
static_cast<Class*>(this)->constrainMatch(m_value);
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +163,7 @@ namespace geode {
|
|||
Result<> isValidValue(ValueType value) {
|
||||
GEODE_INT_CONSTRAIN_SETTING_CAN_IMPL(constrainMinMax, IMinMax<ValueType>);
|
||||
GEODE_INT_CONSTRAIN_SETTING_CAN_IMPL(constrainOneOf, IOneOf<Class, ValueType>);
|
||||
GEODE_INT_CONSTRAIN_SETTING_CAN_IMPL(constrainMatch, IMatch<Class>);
|
||||
GEODE_INT_CONSTRAIN_SETTING_CAN_IMPL(constrainMatch, IMatch<Class, ValueType>);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
@ -238,7 +241,7 @@ namespace geode {
|
|||
value = static_cast<Class*>(this)->getDefault();
|
||||
return Err(
|
||||
"Value must be one of " +
|
||||
container_utils::join(m_oneOf.value(), ", ")
|
||||
utils::container::join(m_oneOf.value(), ", ")
|
||||
);
|
||||
}
|
||||
return Ok();
|
||||
|
@ -260,13 +263,13 @@ namespace geode {
|
|||
}
|
||||
};
|
||||
|
||||
template<class Class>
|
||||
template<class Class, class ValueType>
|
||||
class IMatch {
|
||||
protected:
|
||||
std::optional<std::string> m_matchRegex = std::nullopt;
|
||||
std::optional<ValueType> m_matchRegex = std::nullopt;
|
||||
|
||||
public:
|
||||
Result<> constrainMatch(std::string& value) {
|
||||
Result<> constrainMatch(ValueType& value) {
|
||||
if (m_matchRegex) {
|
||||
auto regex = std::regex(m_matchRegex.value());
|
||||
if (!std::regex_match(value, regex)) {
|
||||
|
@ -280,11 +283,11 @@ namespace geode {
|
|||
}
|
||||
|
||||
Result<> parseMatch(JsonMaybeObject<ModJson>& obj) {
|
||||
obj.has("match").intoAs<std::string>(m_matchRegex);
|
||||
obj.has("match").intoAs<ValueType>(m_matchRegex);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
std::optional<std::string> getMatch() const {
|
||||
std::optional<ValueType> getMatch() const {
|
||||
return m_matchRegex;
|
||||
}
|
||||
};
|
||||
|
@ -354,6 +357,34 @@ namespace geode {
|
|||
}
|
||||
};
|
||||
|
||||
class ICFileFilters {
|
||||
protected:
|
||||
using Filter = utils::file::FilePickOptions::Filter;
|
||||
|
||||
std::optional<std::vector<Filter>> m_filters = std::nullopt;
|
||||
|
||||
public:
|
||||
Result<> parseFileFilters(JsonMaybeObject<ModJson>& obj) {
|
||||
std::vector<Filter> filters {};
|
||||
for (auto& item : obj.has("filters").iterate()) {
|
||||
if (auto iobj = item.obj()) {
|
||||
Filter filter;
|
||||
iobj.has("description").into(filter.description);
|
||||
iobj.has("files").into(filter.files);
|
||||
filters.push_back(filter);
|
||||
}
|
||||
}
|
||||
if (filters.size()) {
|
||||
m_filters = filters;
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
auto getFileFilters() const {
|
||||
return m_filters;
|
||||
}
|
||||
};
|
||||
|
||||
GEODE_INT_DECL_SETTING_CONTROL(Input, hasInput, true, "input");
|
||||
}
|
||||
|
||||
|
@ -390,7 +421,7 @@ namespace geode {
|
|||
class GEODE_DLL StringSetting :
|
||||
public GeodeSetting<StringSetting, std::string, SettingType::String>,
|
||||
public IOneOf<StringSetting, std::string>,
|
||||
public IMatch<StringSetting>,
|
||||
public IMatch<StringSetting, std::string>,
|
||||
public std::enable_shared_from_this<StringSetting>
|
||||
{
|
||||
public:
|
||||
|
@ -399,6 +430,7 @@ namespace geode {
|
|||
|
||||
class GEODE_DLL FileSetting :
|
||||
public GeodeSetting<FileSetting, ghc::filesystem::path, SettingType::File>,
|
||||
public ICFileFilters,
|
||||
public std::enable_shared_from_this<FileSetting>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -9,6 +9,20 @@ namespace geode {
|
|||
template<class Json>
|
||||
struct JsonChecker;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_iterable : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_iterable<T,
|
||||
std::void_t<
|
||||
decltype(std::begin(std::declval<T>())),
|
||||
decltype(std::end(std::declval<T>()))
|
||||
>
|
||||
> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_iterable_v = is_iterable<T>::value;
|
||||
|
||||
namespace {
|
||||
using value_t = nlohmann::detail::value_t;
|
||||
|
||||
|
@ -43,11 +57,13 @@ namespace geode {
|
|||
return value_t::number_integer;
|
||||
}
|
||||
else if constexpr (
|
||||
std::is_same_v<T, std::string> ||
|
||||
std::is_same_v<T, const char*>
|
||||
std::is_constructible_v<T, std::string>
|
||||
) {
|
||||
return value_t::string;
|
||||
}
|
||||
else if constexpr (is_iterable_v<T>) {
|
||||
return value_t::array;
|
||||
}
|
||||
return value_t::null;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace geode::container_utils {
|
||||
namespace geode::utils::container {
|
||||
/**
|
||||
* Check if a container contains an element by value.
|
||||
* @param vec The vector to check.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "types.hpp"
|
||||
#include "fs/filesystem.hpp"
|
||||
|
||||
namespace geode::file_utils {
|
||||
namespace geode::utils::file {
|
||||
GEODE_DLL Result<std::string> readString(std::string const& path);
|
||||
GEODE_DLL Result<std::string> readString(std::wstring const& path);
|
||||
GEODE_DLL Result<std::string> readString(ghc::filesystem::path const& path);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace geode::map_utils {
|
||||
namespace geode::utils::map {
|
||||
/**
|
||||
* Returns true if the map contains
|
||||
* a value matching `containFunc`.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <Geode/DefaultInclude.hpp>
|
||||
#include "Result.hpp"
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "fs/filesystem.hpp"
|
||||
|
@ -12,9 +13,34 @@ namespace geode::utils::clipboard {
|
|||
GEODE_DLL std::string read();
|
||||
}
|
||||
|
||||
namespace geode::utils::dirs {
|
||||
namespace geode::utils::file {
|
||||
GEODE_DLL ghc::filesystem::path geodeRoot();
|
||||
GEODE_DLL bool openFolder(ghc::filesystem::path const& path);
|
||||
|
||||
enum class PickMode {
|
||||
OpenFile,
|
||||
SaveFile,
|
||||
OpenFolder,
|
||||
};
|
||||
|
||||
struct FilePickOptions {
|
||||
struct Filter {
|
||||
// Name of the filter
|
||||
std::string description;
|
||||
// Extensions (*.txt, *.doc, *.mp3, etc.)
|
||||
std::unordered_set<std::string> files;
|
||||
};
|
||||
ghc::filesystem::path defaultPath;
|
||||
std::vector<Filter> filters;
|
||||
};
|
||||
|
||||
GEODE_DLL Result<ghc::filesystem::path> pickFile(
|
||||
PickMode mode,
|
||||
FilePickOptions const& options
|
||||
);
|
||||
GEODE_DLL Result<std::vector<ghc::filesystem::path>> pickFiles(
|
||||
FilePickOptions const& options
|
||||
);
|
||||
}
|
||||
|
||||
namespace geode::utils::web {
|
||||
|
|
|
@ -5,117 +5,115 @@
|
|||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace geode {
|
||||
namespace string_utils {
|
||||
/**
|
||||
* Convert std::wstring to std::string (UTF-8)
|
||||
* @param str String to convert
|
||||
* @returns std::string
|
||||
*/
|
||||
GEODE_DLL std::string wideToUtf8(std::wstring const& str);
|
||||
/**
|
||||
* Convert std::string (UTF-8) to std::wstring
|
||||
* @param str String to convert
|
||||
* @returns std::wstring
|
||||
*/
|
||||
GEODE_DLL std::wstring utf8ToWide(std::string const& str);
|
||||
namespace geode::utils::string {
|
||||
/**
|
||||
* Convert std::wstring to std::string (UTF-8)
|
||||
* @param str String to convert
|
||||
* @returns std::string
|
||||
*/
|
||||
GEODE_DLL std::string wideToUtf8(std::wstring const& str);
|
||||
/**
|
||||
* Convert std::string (UTF-8) to std::wstring
|
||||
* @param str String to convert
|
||||
* @returns std::wstring
|
||||
*/
|
||||
GEODE_DLL std::wstring utf8ToWide(std::string const& str);
|
||||
|
||||
GEODE_DLL std::string & toLowerIP(std::string & str);
|
||||
GEODE_DLL std::wstring& toLowerIP(std::wstring& str);
|
||||
GEODE_DLL std::string & toLowerIP(std::string & str);
|
||||
GEODE_DLL std::wstring& toLowerIP(std::wstring& str);
|
||||
|
||||
GEODE_DLL std::string toLower(std::string const& str);
|
||||
GEODE_DLL std::wstring toLower(std::wstring const& str);
|
||||
GEODE_DLL std::string toLower(std::string const& str);
|
||||
GEODE_DLL std::wstring toLower(std::wstring const& str);
|
||||
|
||||
GEODE_DLL std::string & toUpperIP(std::string & str);
|
||||
GEODE_DLL std::wstring& toUpperIP(std::wstring& str);
|
||||
GEODE_DLL std::string & toUpperIP(std::string & str);
|
||||
GEODE_DLL std::wstring& toUpperIP(std::wstring& str);
|
||||
|
||||
GEODE_DLL std::string toUpper(std::string const& str);
|
||||
GEODE_DLL std::wstring toUpper(std::wstring const& str);
|
||||
GEODE_DLL std::string toUpper(std::string const& str);
|
||||
GEODE_DLL std::wstring toUpper(std::wstring const& str);
|
||||
|
||||
GEODE_DLL std::string& replaceIP(
|
||||
std::string & str,
|
||||
std::string const& orig,
|
||||
std::string const& repl
|
||||
);
|
||||
GEODE_DLL std::wstring& replaceIP(
|
||||
std::wstring & str,
|
||||
std::wstring const& orig,
|
||||
std::wstring const& repl
|
||||
);
|
||||
GEODE_DLL std::string& replaceIP(
|
||||
std::string & str,
|
||||
std::string const& orig,
|
||||
std::string const& repl
|
||||
);
|
||||
GEODE_DLL std::wstring& replaceIP(
|
||||
std::wstring & str,
|
||||
std::wstring const& orig,
|
||||
std::wstring const& repl
|
||||
);
|
||||
|
||||
GEODE_DLL std::string replace(
|
||||
std::string const& str,
|
||||
std::string const& orig,
|
||||
std::string const& repl
|
||||
);
|
||||
GEODE_DLL std::wstring replace(
|
||||
std::wstring const& str,
|
||||
std::wstring const& orig,
|
||||
std::wstring const& repl
|
||||
);
|
||||
GEODE_DLL std::string replace(
|
||||
std::string const& str,
|
||||
std::string const& orig,
|
||||
std::string const& repl
|
||||
);
|
||||
GEODE_DLL std::wstring replace(
|
||||
std::wstring const& str,
|
||||
std::wstring const& orig,
|
||||
std::wstring const& repl
|
||||
);
|
||||
|
||||
GEODE_DLL std::vector<std::string> split(
|
||||
std::string const& str,
|
||||
std::string const& split
|
||||
);
|
||||
GEODE_DLL std::vector<std::wstring> split(
|
||||
std::wstring const& str,
|
||||
std::wstring const& split
|
||||
);
|
||||
GEODE_DLL std::vector<std::string> split(
|
||||
std::string const& str,
|
||||
std::string const& split
|
||||
);
|
||||
GEODE_DLL std::vector<std::wstring> split(
|
||||
std::wstring const& str,
|
||||
std::wstring const& split
|
||||
);
|
||||
|
||||
GEODE_DLL std::vector<char> split(std::string const& str);
|
||||
GEODE_DLL std::vector<wchar_t> split(std::wstring const& str);
|
||||
GEODE_DLL std::vector<char> split(std::string const& str);
|
||||
GEODE_DLL std::vector<wchar_t> split(std::wstring const& str);
|
||||
|
||||
GEODE_DLL bool contains(std::string const& str, std::string const& subs);
|
||||
GEODE_DLL bool contains(std::wstring const& str, std::wstring const& subs);
|
||||
GEODE_DLL bool contains(std::string const& str, std::string const& subs);
|
||||
GEODE_DLL bool contains(std::wstring const& str, std::wstring const& subs);
|
||||
|
||||
GEODE_DLL bool contains(std::string const& str, char c);
|
||||
GEODE_DLL bool contains(std::wstring const& str, wchar_t c);
|
||||
GEODE_DLL bool contains(std::string const& str, char c);
|
||||
GEODE_DLL bool contains(std::wstring const& str, wchar_t c);
|
||||
|
||||
GEODE_DLL bool containsAny(
|
||||
std::string const& str,
|
||||
std::vector<std::string> const& subs
|
||||
);
|
||||
GEODE_DLL bool containsAny(
|
||||
std::wstring const& str,
|
||||
std::vector<std::wstring> const& subs
|
||||
);
|
||||
GEODE_DLL bool containsAny(
|
||||
std::string const& str,
|
||||
std::vector<std::string> const& subs
|
||||
);
|
||||
GEODE_DLL bool containsAny(
|
||||
std::wstring const& str,
|
||||
std::vector<std::wstring> const& subs
|
||||
);
|
||||
|
||||
GEODE_DLL bool containsAll(
|
||||
std::string const& str,
|
||||
std::vector<std::string> const& subs
|
||||
);
|
||||
GEODE_DLL bool containsAll(
|
||||
std::wstring const& str,
|
||||
std::vector<std::wstring> const& subs
|
||||
);
|
||||
GEODE_DLL bool containsAll(
|
||||
std::string const& str,
|
||||
std::vector<std::string> const& subs
|
||||
);
|
||||
GEODE_DLL bool containsAll(
|
||||
std::wstring const& str,
|
||||
std::vector<std::wstring> const& subs
|
||||
);
|
||||
|
||||
GEODE_DLL size_t count(std::string const& str, char c);
|
||||
GEODE_DLL size_t count(std::wstring const& str, wchar_t c);
|
||||
GEODE_DLL size_t count(std::string const& str, char c);
|
||||
GEODE_DLL size_t count(std::wstring const& str, wchar_t c);
|
||||
|
||||
GEODE_DLL std::string & trimLeftIP(std::string & str);
|
||||
GEODE_DLL std::wstring& trimLeftIP(std::wstring& str);
|
||||
GEODE_DLL std::string & trimRightIP(std::string & str);
|
||||
GEODE_DLL std::wstring& trimRightIP(std::wstring& str);
|
||||
GEODE_DLL std::string & trimIP(std::string & str);
|
||||
GEODE_DLL std::wstring& trimIP(std::wstring& str);
|
||||
GEODE_DLL std::string & trimLeftIP(std::string & str);
|
||||
GEODE_DLL std::wstring& trimLeftIP(std::wstring& str);
|
||||
GEODE_DLL std::string & trimRightIP(std::string & str);
|
||||
GEODE_DLL std::wstring& trimRightIP(std::wstring& str);
|
||||
GEODE_DLL std::string & trimIP(std::string & str);
|
||||
GEODE_DLL std::wstring& trimIP(std::wstring& str);
|
||||
|
||||
GEODE_DLL std::string trimLeft(std::string const& str);
|
||||
GEODE_DLL std::wstring trimLeft(std::wstring const& str);
|
||||
GEODE_DLL std::string trimRight(std::string const& str);
|
||||
GEODE_DLL std::wstring trimRight(std::wstring const& str);
|
||||
GEODE_DLL std::string trim(std::string const& str);
|
||||
GEODE_DLL std::wstring trim(std::wstring const& str);
|
||||
GEODE_DLL std::string trimLeft(std::string const& str);
|
||||
GEODE_DLL std::wstring trimLeft(std::wstring const& str);
|
||||
GEODE_DLL std::string trimRight(std::string const& str);
|
||||
GEODE_DLL std::wstring trimRight(std::wstring const& str);
|
||||
GEODE_DLL std::string trim(std::string const& str);
|
||||
GEODE_DLL std::wstring trim(std::wstring const& str);
|
||||
|
||||
GEODE_DLL std::string & normalizeIP(std::string & str);
|
||||
GEODE_DLL std::wstring& normalizeIP(std::wstring & str);
|
||||
GEODE_DLL std::string normalize(std::string const& str);
|
||||
GEODE_DLL std::wstring normalize(std::wstring const& str);
|
||||
GEODE_DLL std::string & normalizeIP(std::string & str);
|
||||
GEODE_DLL std::wstring& normalizeIP(std::wstring & str);
|
||||
GEODE_DLL std::string normalize(std::string const& str);
|
||||
GEODE_DLL std::wstring normalize(std::wstring const& str);
|
||||
|
||||
GEODE_DLL bool startsWith(std::string const& str, std::string const& prefix);
|
||||
GEODE_DLL bool startsWith(std::wstring const& str, std::wstring const& prefix);
|
||||
GEODE_DLL bool endsWith(std::string const& str, std::string const& suffix);
|
||||
GEODE_DLL bool endsWith(std::wstring const& str, std::wstring const& suffix);
|
||||
}
|
||||
GEODE_DLL bool startsWith(std::string const& str, std::string const& prefix);
|
||||
GEODE_DLL bool startsWith(std::wstring const& str, std::wstring const& prefix);
|
||||
GEODE_DLL bool endsWith(std::string const& str, std::string const& suffix);
|
||||
GEODE_DLL bool endsWith(std::wstring const& str, std::wstring const& suffix);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
namespace geode::vector_utils {
|
||||
namespace geode::utils::vector {
|
||||
/**
|
||||
* Check if a vector contains an element by value.
|
||||
* @param vec The vector to check.
|
||||
|
@ -229,7 +229,7 @@ namespace geode::vector_utils {
|
|||
*/
|
||||
template<class T>
|
||||
void insertBefore(std::vector<T> & vec, T const& item, T const& before) {
|
||||
vec.insert(vector_utils::indexOf(vec, before), item);
|
||||
vec.insert(utils::vector::indexOf(vec, before), item);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -241,6 +241,6 @@ namespace geode::vector_utils {
|
|||
*/
|
||||
template<class T>
|
||||
void insertAfter(std::vector<T> & vec, T const& item, T const& after) {
|
||||
vec.insert(vector_utils::indexOf(vec, after) + 1, item);
|
||||
vec.insert(utils::vector::indexOf(vec, after) + 1, item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
template<class Json = nlohmann::json>
|
||||
static Result<Json> readJSON(ghc::filesystem::path const& path) {
|
||||
auto indexJsonData = file_utils::readString(path);
|
||||
auto indexJsonData = utils::file::readString(path);
|
||||
if (!indexJsonData) {
|
||||
return Err("Unable to read " + path.string());
|
||||
}
|
||||
|
@ -36,8 +36,8 @@ static Result<> unzipTo(
|
|||
// getAllFiles returns the directories
|
||||
// aswell now
|
||||
if (
|
||||
string_utils::endsWith(file, "\\") ||
|
||||
string_utils::endsWith(file, "/")
|
||||
utils::string::endsWith(file, "\\") ||
|
||||
utils::string::endsWith(file, "/")
|
||||
) continue;
|
||||
|
||||
auto zipPath = file;
|
||||
|
@ -62,7 +62,7 @@ static Result<> unzipTo(
|
|||
if (!data || !size) {
|
||||
return Err("Unable to read \"" + std::string(zipPath) + "\"");
|
||||
}
|
||||
auto wrt = file_utils::writeBinary(
|
||||
auto wrt = utils::file::writeBinary(
|
||||
to / file,
|
||||
byte_array(data, data + size)
|
||||
);
|
||||
|
@ -75,7 +75,7 @@ static Result<> unzipTo(
|
|||
}
|
||||
|
||||
static PlatformID platformFromString(std::string const& str) {
|
||||
switch (hash(string_utils::trim(string_utils::toLower(str)).c_str())) {
|
||||
switch (hash(utils::string::trim(utils::string::toLower(str)).c_str())) {
|
||||
default:
|
||||
case hash("unknown"): return PlatformID::Unknown;
|
||||
case hash("windows"): return PlatformID::Windows;
|
||||
|
@ -165,7 +165,7 @@ void Index::updateIndexThread(bool force) {
|
|||
// read sha of currently installed commit
|
||||
std::string currentCommitSHA = "";
|
||||
if (ghc::filesystem::exists(indexDir / "current")) {
|
||||
auto data = file_utils::readString(indexDir / "current");
|
||||
auto data = utils::file::readString(indexDir / "current");
|
||||
if (data) {
|
||||
currentCommitSHA = data.value();
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ void Index::updateIndexThread(bool force) {
|
|||
// different sha
|
||||
if (force || currentCommitSHA != upcomingCommitSHA) {
|
||||
// save new sha in file
|
||||
file_utils::writeString(indexDir / "current", upcomingCommitSHA);
|
||||
utils::file::writeString(indexDir / "current", upcomingCommitSHA);
|
||||
|
||||
// download latest commit (by downloading
|
||||
// the repo as a zip)
|
||||
|
@ -520,7 +520,7 @@ Result<InstallTicket*> Index::installItems(
|
|||
if (!list) {
|
||||
return Err(list.error());
|
||||
}
|
||||
vector_utils::push(ids, list.value());
|
||||
utils::vector::push(ids, list.value());
|
||||
}
|
||||
return Ok(new InstallTicket(this, ids, progress));
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ void InstallTicket::install(std::string const& id) {
|
|||
}
|
||||
|
||||
// check for 404
|
||||
auto notFound = file_utils::readString(tempFile);
|
||||
auto notFound = utils::file::readString(tempFile);
|
||||
if (notFound && notFound.value() == "Not Found") {
|
||||
try { ghc::filesystem::remove(tempFile); } catch(...) {}
|
||||
return this->postProgress(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "fetch.hpp"
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace fetch_utils {
|
||||
namespace geode::utils::fetch {
|
||||
static size_t writeData(char* data, size_t size, size_t nmemb, void* str) {
|
||||
as<std::string*>(str)->append(data, size * nmemb);
|
||||
return size * nmemb;
|
||||
|
@ -35,12 +35,12 @@ Result<> fetchFile(
|
|||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fetch_utils::writeBinaryData);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, utils::fetch::writeBinaryData);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "github_api/1.0");
|
||||
if (prog) {
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, fetch_utils::progress);
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, utils::fetch::progress);
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &prog);
|
||||
}
|
||||
auto res = curl_easy_perform(curl);
|
||||
|
@ -68,7 +68,7 @@ Result<std::string> fetch(std::string const& url) {
|
|||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fetch_utils::writeData);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, utils::fetch::writeData);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "github_api/1.0");
|
||||
auto res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK) {
|
||||
|
|
|
@ -159,7 +159,7 @@ void InternalLoader::platformMessageBox(const char* title, const char* info) {
|
|||
|
||||
void InternalLoader::setupPlatformConsole() {
|
||||
ghc::filesystem::path(getpwuid(getuid())->pw_dir);
|
||||
freopen(ghc::filesystem::path(utils::dirs::geodeRoot() / "geode_log.txt").string().c_str(),"w",stdout);
|
||||
freopen(ghc::filesystem::path(utils::file::geodeRoot() / "geode_log.txt").string().c_str(),"w",stdout);
|
||||
InternalLoader::
|
||||
m_platformConsoleReady = true;
|
||||
}
|
||||
|
|
|
@ -256,11 +256,11 @@ static void printMods(std::ostream& stream) {
|
|||
|
||||
static LONG WINAPI exceptionHandler(LPEXCEPTION_POINTERS info) {
|
||||
// make sure crashlog directory exists
|
||||
file_utils::createDirectoryAll(crashlog::getCrashLogDirectory());
|
||||
utils::file::createDirectoryAll(crashlog::getCrashLogDirectory());
|
||||
|
||||
// add a file to let Geode know on next launch that it crashed previously
|
||||
// this could also be done by saving a loader setting or smth but eh.
|
||||
file_utils::writeBinary(
|
||||
utils::file::writeBinary(
|
||||
crashlog::getCrashLogDirectory() + "/last-crashed", {}
|
||||
);
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ USE_GEODE_NAMESPACE();
|
|||
std::vector<BasicEventHandler*> Event::handlers = {};
|
||||
|
||||
void BasicEventHandler::listen() {
|
||||
if (!vector_utils::contains(Event::handlers, this))
|
||||
if (!utils::vector::contains(Event::handlers, this))
|
||||
Event::handlers.push_back(this);
|
||||
}
|
||||
|
||||
void BasicEventHandler::unlisten() {
|
||||
vector_utils::erase(Event::handlers, this);
|
||||
utils::vector::erase(Event::handlers, this);
|
||||
}
|
||||
|
||||
Event::~Event() {}
|
||||
|
|
|
@ -58,7 +58,7 @@ Result<> Mod::disableHook(Hook* hook) {
|
|||
Result<> Mod::removeHook(Hook* hook) {
|
||||
auto res = this->disableHook(hook);
|
||||
if (res) {
|
||||
vector_utils::erase<Hook*>(this->m_hooks, hook);
|
||||
utils::vector::erase<Hook*>(this->m_hooks, hook);
|
||||
delete hook;
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -42,7 +42,7 @@ void Loader::createDirectories() {
|
|||
ghc::filesystem::create_directory(logDir);
|
||||
ghc::filesystem::create_directory(tempDir);
|
||||
|
||||
if (!vector_utils::contains(m_modDirectories, modDir)) {
|
||||
if (!utils::vector::contains(m_modDirectories, modDir)) {
|
||||
m_modDirectories.push_back(modDir);
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ size_t Loader::loadModsFromDirectory(
|
|||
}
|
||||
|
||||
// skip this entry if it's already loaded
|
||||
if (map_utils::contains<std::string, Mod*>(
|
||||
if (utils::map::contains<std::string, Mod*>(
|
||||
m_mods,
|
||||
[entry](Mod* p) -> bool {
|
||||
return p->m_info.m_path == entry.path();
|
||||
|
@ -195,7 +195,7 @@ Result<> Loader::saveSettings() {
|
|||
json["succesfully-closed"] = true;
|
||||
InternalLoader::get()->saveInfoAlerts(json);
|
||||
auto path = this->getGeodeSaveDirectory() / "mods.json";
|
||||
return file_utils::writeString(path, json.dump(4));
|
||||
return utils::file::writeString(path, json.dump(4));
|
||||
}
|
||||
|
||||
Result<> Loader::loadSettings() {
|
||||
|
@ -204,7 +204,7 @@ Result<> Loader::loadSettings() {
|
|||
return Ok();
|
||||
}
|
||||
|
||||
auto read = file_utils::readString(path);
|
||||
auto read = utils::file::readString(path);
|
||||
if (!read) {
|
||||
return read;
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ Mod* Loader::getLoadedMod(std::string const& id) const {
|
|||
}
|
||||
|
||||
std::vector<Mod*> Loader::getAllMods() const {
|
||||
return map_utils::getValues(m_mods);
|
||||
return utils::map::getValues(m_mods);
|
||||
}
|
||||
|
||||
std::vector<Loader::FailedModInfo> Loader::getFailedMods() const {
|
||||
|
@ -367,7 +367,7 @@ void Loader::pushLog(LogPtr* logptr) {
|
|||
}
|
||||
|
||||
void Loader::popLog(LogPtr* log) {
|
||||
vector_utils::erase(m_logs, log);
|
||||
utils::vector::erase(m_logs, log);
|
||||
delete log;
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,7 @@ std::vector<LogPtr*> Loader::getLogs(
|
|||
std::vector<LogPtr*> logs;
|
||||
|
||||
for (auto const& log : m_logs) {
|
||||
if (vector_utils::contains<Severity>(
|
||||
if (utils::vector::contains<Severity>(
|
||||
severityFilter, log->getSeverity()
|
||||
)) {
|
||||
logs.push_back(log);
|
||||
|
@ -420,7 +420,7 @@ ghc::filesystem::path Loader::getSaveDirectory() const {
|
|||
}
|
||||
|
||||
ghc::filesystem::path Loader::getGeodeDirectory() const {
|
||||
return geode::utils::dirs::geodeRoot() / GEODE_DIRECTORY;
|
||||
return geode::utils::file::geodeRoot() / GEODE_DIRECTORY;
|
||||
}
|
||||
|
||||
ghc::filesystem::path Loader::getGeodeSaveDirectory() const {
|
||||
|
|
|
@ -57,7 +57,7 @@ Result<> Mod::loadSettings() {
|
|||
// Check if settings exist
|
||||
auto settPath = m_saveDirPath / "settings.json";
|
||||
if (ghc::filesystem::exists(settPath)) {
|
||||
auto settData = file_utils::readString(settPath);
|
||||
auto settData = utils::file::readString(settPath);
|
||||
if (!settData) return settData;
|
||||
try {
|
||||
// parse settings.json
|
||||
|
@ -94,7 +94,7 @@ Result<> Mod::loadSettings() {
|
|||
if (!ghc::filesystem::exists(dsPath)) {
|
||||
m_dataStore = m_info.m_defaultDataStore;
|
||||
} else {
|
||||
auto dsData = file_utils::readString(dsPath);
|
||||
auto dsData = utils::file::readString(dsPath);
|
||||
if (!dsData) return dsData;
|
||||
try {
|
||||
m_dataStore = nlohmann::json::parse(dsData.value());
|
||||
|
@ -114,14 +114,14 @@ Result<> Mod::saveSettings() {
|
|||
return Err("Unable to save setting \"" + key + "\"");
|
||||
}
|
||||
}
|
||||
auto sw = file_utils::writeString(settPath, json.dump(4));
|
||||
auto sw = utils::file::writeString(settPath, json.dump(4));
|
||||
if (!sw) {
|
||||
return sw;
|
||||
}
|
||||
|
||||
// datastore
|
||||
auto dsPath = m_saveDirPath / "ds.json";
|
||||
auto dw = file_utils::writeString(dsPath, m_dataStore.dump(4));
|
||||
auto dw = utils::file::writeString(dsPath, m_dataStore.dump(4));
|
||||
if (!dw) {
|
||||
return dw;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ Result<> Mod::createTempDir() {
|
|||
if (!data || !size) {
|
||||
return Err<>("Unable to read \"" + std::string(file) + "\"");
|
||||
}
|
||||
auto wrt = file_utils::writeBinary(
|
||||
auto wrt = utils::file::writeBinary(
|
||||
tempPath / file,
|
||||
byte_array(data, data + size)
|
||||
);
|
||||
|
@ -531,7 +531,7 @@ void Mod::logInfo(
|
|||
}
|
||||
|
||||
bool Mod::depends(std::string const& id) const {
|
||||
return vector_utils::contains<Dependency>(
|
||||
return utils::vector::contains<Dependency>(
|
||||
this->m_info.m_dependencies,
|
||||
[id](Dependency t) -> bool { return t.m_id == id; }
|
||||
);
|
||||
|
|
|
@ -8,7 +8,7 @@ USE_GEODE_NAMESPACE();
|
|||
|
||||
static std::string sanitizeDetailsData(unsigned char* start, unsigned char* end) {
|
||||
// delete CRLF
|
||||
return string_utils::replace(std::string(start, end), "\r", "");
|
||||
return utils::string::replace(std::string(start, end), "\r", "");
|
||||
}
|
||||
|
||||
Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
||||
|
@ -99,7 +99,7 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
|||
if (
|
||||
root.has("binary") &&
|
||||
autoEndBinaryName &&
|
||||
!string_utils::endsWith(info.m_binaryName, GEODE_PLATFORM_EXTENSION)
|
||||
!utils::string::endsWith(info.m_binaryName, GEODE_PLATFORM_EXTENSION)
|
||||
) {
|
||||
info.m_binaryName += GEODE_PLATFORM_EXTENSION;
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ Result<ModInfo> ModInfo::create(ModJson const& json) {
|
|||
|
||||
Result<ModInfo> ModInfo::createFromFile(ghc::filesystem::path const& path) {
|
||||
try {
|
||||
auto read = file_utils::readString(path);
|
||||
auto read = utils::file::readString(path);
|
||||
if (!read) return Err(read.error());
|
||||
try {
|
||||
auto res = ModInfo::create(ModJson::parse(read.value()));
|
||||
|
|
|
@ -34,7 +34,7 @@ Result<Patch*> Mod::patch(void* address, byte_array data) {
|
|||
|
||||
Result<> Mod::unpatch(Patch* patch) {
|
||||
if (patch->restore()) {
|
||||
vector_utils::erase<Patch*>(m_patches, patch);
|
||||
utils::vector::erase<Patch*>(m_patches, patch);
|
||||
delete patch;
|
||||
return Ok<>();
|
||||
}
|
||||
|
|
|
@ -3,24 +3,24 @@
|
|||
USE_GEODE_NAMESPACE();
|
||||
|
||||
std::string expandKnownLink(std::string const& link) {
|
||||
switch (hash(string_utils::toLower(link).c_str())) {
|
||||
switch (hash(utils::string::toLower(link).c_str())) {
|
||||
case hash("github"):
|
||||
if (!string_utils::contains(link, "/")) {
|
||||
if (!utils::string::contains(link, "/")) {
|
||||
return "https://github.com/" + link;
|
||||
} break;
|
||||
|
||||
case hash("youtube"):
|
||||
if (!string_utils::contains(link, "/")) {
|
||||
if (!utils::string::contains(link, "/")) {
|
||||
return "https://youtube.com/channel/" + link;
|
||||
} break;
|
||||
|
||||
case hash("twitter"):
|
||||
if (!string_utils::contains(link, "/")) {
|
||||
if (!utils::string::contains(link, "/")) {
|
||||
return "https://twitter.com/" + link;
|
||||
} break;
|
||||
|
||||
case hash("newgrounds"):
|
||||
if (!string_utils::contains(link, "/")) {
|
||||
if (!utils::string::contains(link, "/")) {
|
||||
return "https://" + link + ".newgrounds.com";
|
||||
} break;
|
||||
}
|
||||
|
|
|
@ -418,7 +418,7 @@ void ModInfoLayer::onInstallMod(CCObject*) {
|
|||
this,
|
||||
"Install",
|
||||
"The following <cb>mods</c> will be installed: " +
|
||||
vector_utils::join(m_ticket->getInstallList(), ",") + ".",
|
||||
utils::vector::join(m_ticket->getInstallList(), ",") + ".",
|
||||
"Cancel", "OK", 360.f
|
||||
);
|
||||
layer->setTag(TAG_CONFIRM_INSTALL);
|
||||
|
|
|
@ -412,7 +412,7 @@ void ModListLayer::onReload(CCObject*) {
|
|||
}
|
||||
|
||||
void ModListLayer::onOpenFolder(CCObject*) {
|
||||
dirs::openFolder(
|
||||
file::openFolder(
|
||||
ghc::filesystem::canonical(Loader::get()->getGeodeDirectory() / "mods")
|
||||
);
|
||||
}
|
||||
|
|
|
@ -443,9 +443,9 @@ bool ModListView::filter(ModInfo const& info, ModListQuery const& query) {
|
|||
if (!query.m_searchFilter) return true;
|
||||
auto check = [query](SearchFlags flag, std::string const& name) -> bool {
|
||||
if (!(query.m_searchFlags & flag)) return false;
|
||||
return string_utils::contains(
|
||||
string_utils::toLower(name),
|
||||
string_utils::toLower(query.m_searchFilter.value())
|
||||
return utils::string::contains(
|
||||
utils::string::toLower(name),
|
||||
utils::string::toLower(query.m_searchFilter.value())
|
||||
);
|
||||
};
|
||||
if (check(SearchFlag::Name, info.m_name)) return true;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "GeodeSettingNode.hpp"
|
||||
#include <Geode/utils/platform.hpp>
|
||||
|
||||
// BoolSettingNode
|
||||
|
||||
|
@ -111,12 +112,34 @@ void FileSettingNode::valueChanged(bool updateText) {
|
|||
}
|
||||
|
||||
bool FileSettingNode::setup(std::shared_ptr<FileSetting> setting, float width) {
|
||||
m_input = InputNode::create(width / 2 - 10.f, "Path to File", "chatFont.fnt");
|
||||
m_input->setPosition({ -(width / 2 - 70.f) / 2, .0f });
|
||||
m_input = InputNode::create(width / 2 - 30.f, "Path to File", "chatFont.fnt");
|
||||
m_input->setPosition({ -(width / 2 - 80.f) / 2 - 15.f, .0f });
|
||||
m_input->setScale(.65f);
|
||||
m_input->getInput()->setDelegate(this);
|
||||
m_menu->addChild(m_input);
|
||||
|
||||
auto fileBtnSpr = CCSprite::createWithSpriteFrameName("gj_folderBtn_001.png");
|
||||
fileBtnSpr->setScale(.5f);
|
||||
|
||||
auto fileBtn = CCMenuItemSpriteExtra::create(
|
||||
fileBtnSpr, this, makeMenuSelector([this, setting](CCObject*) {
|
||||
if (auto path = file::pickFile(
|
||||
file::PickMode::OpenFile,
|
||||
{
|
||||
file::geodeRoot(),
|
||||
setting->getFileFilters().value_or(
|
||||
std::vector<file::FilePickOptions::Filter>()
|
||||
)
|
||||
}
|
||||
)) {
|
||||
m_uncommittedValue = path.value();
|
||||
this->valueChanged(true);
|
||||
}
|
||||
})
|
||||
);
|
||||
fileBtn->setPosition(.0f, .0f);
|
||||
m_menu->addChild(fileBtn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,9 +66,9 @@ public:
|
|||
|
||||
|
||||
Result<ccColor3B> colorForIdentifier(std::string const& tag) {
|
||||
if (string_utils::contains(tag, ' ')) {
|
||||
auto hexStr = string_utils::split(
|
||||
string_utils::normalize(tag), " "
|
||||
if (utils::string::contains(tag, ' ')) {
|
||||
auto hexStr = utils::string::split(
|
||||
utils::string::normalize(tag), " "
|
||||
).at(1);
|
||||
try {
|
||||
auto hex = std::stoi(hexStr, nullptr, 16);
|
||||
|
@ -224,7 +224,7 @@ struct MDParser {
|
|||
// rendering is done since the position of the
|
||||
// rendered labels may change after alignments
|
||||
// are adjusted
|
||||
vector_utils::push(s_codeSpans, rendered);
|
||||
utils::vector::push(s_codeSpans, rendered);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -243,7 +243,7 @@ struct MDParser {
|
|||
auto rendered = renderer->renderStringInteractive(
|
||||
text,
|
||||
textarea,
|
||||
string_utils::startsWith(s_lastLink, "user:") ?
|
||||
utils::string::startsWith(s_lastLink, "user:") ?
|
||||
menu_selector(MDTextArea::onGDProfile) :
|
||||
menu_selector(MDTextArea::onLink)
|
||||
);
|
||||
|
@ -254,7 +254,7 @@ struct MDParser {
|
|||
renderer->popColor();
|
||||
} else if (s_lastImage.size()) {
|
||||
bool isFrame = false;
|
||||
if (string_utils::startsWith(s_lastImage, "frame:")) {
|
||||
if (utils::string::startsWith(s_lastImage, "frame:")) {
|
||||
s_lastImage = s_lastImage.substr(s_lastImage.find(":") + 1);
|
||||
isFrame = true;
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ struct MDParser {
|
|||
|
||||
case MD_TEXTTYPE::MD_TEXT_HTML: {
|
||||
if (text.size() > 2) {
|
||||
auto tag = string_utils::trim(text.substr(1, text.size() - 2));
|
||||
auto tag = utils::string::trim(text.substr(1, text.size() - 2));
|
||||
auto isClosing = tag.front() == '/';
|
||||
if (isClosing) tag = tag.substr(1);
|
||||
if (tag.front() != 'c') {
|
||||
|
|
|
@ -438,7 +438,7 @@ Notification* NotificationBuilder::show() {
|
|||
bool NotificationManager::isInQueue(Notification* notification) {
|
||||
auto location = notification->m_location;
|
||||
if (m_notifications.count(location)) {
|
||||
return vector_utils::contains(
|
||||
return utils::vector::contains(
|
||||
m_notifications.at(location), Ref(notification)
|
||||
);
|
||||
}
|
||||
|
@ -458,7 +458,7 @@ void NotificationManager::push(Notification* notification) {
|
|||
void NotificationManager::pop(Notification* notification) {
|
||||
auto location = notification->m_location;
|
||||
if (m_notifications.count(location)) {
|
||||
vector_utils::erase(
|
||||
utils::vector::erase(
|
||||
m_notifications.at(location), Ref(notification)
|
||||
);
|
||||
if (!m_notifications.at(location).size()) {
|
||||
|
|
|
@ -431,12 +431,12 @@ std::vector<TextRenderer::Label> TextRenderer::renderStringEx(
|
|||
if (!createLabel()) return {};
|
||||
|
||||
bool firstLine = true;
|
||||
for (auto line : string_utils::split(str, "\n")) {
|
||||
for (auto line : utils::string::split(str, "\n")) {
|
||||
if (!firstLine && !nextLine()) {
|
||||
return {};
|
||||
}
|
||||
firstLine = false;
|
||||
for (auto word : string_utils::split(line, " ")) {
|
||||
for (auto word : utils::string::split(line, " ")) {
|
||||
// add extra space in front of word if not on
|
||||
// new line
|
||||
if (!newLine) word = " " + word;
|
||||
|
@ -444,8 +444,8 @@ std::vector<TextRenderer::Label> TextRenderer::renderStringEx(
|
|||
|
||||
// update capitalization
|
||||
switch (caps) {
|
||||
case TextCapitalization::AllUpper: string_utils::toUpperIP(word); break;
|
||||
case TextCapitalization::AllLower: string_utils::toLowerIP(word); break;
|
||||
case TextCapitalization::AllUpper: utils::string::toUpperIP(word); break;
|
||||
case TextCapitalization::AllLower: utils::string::toLowerIP(word); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
@ -455,7 +455,7 @@ std::vector<TextRenderer::Label> TextRenderer::renderStringEx(
|
|||
// try to create a new line
|
||||
if (!nextLine()) return {};
|
||||
|
||||
if (string_utils::startsWith(word, " ")) word = word.substr(1);
|
||||
if (utils::string::startsWith(word, " ")) word = word.substr(1);
|
||||
newLine = false;
|
||||
|
||||
// try to render on new line
|
||||
|
@ -472,7 +472,7 @@ std::vector<TextRenderer::Label> TextRenderer::renderStringEx(
|
|||
) {
|
||||
if (!nextLine()) return {};
|
||||
|
||||
if (string_utils::startsWith(word, " ")) word = word.substr(1);
|
||||
if (utils::string::startsWith(word, " ")) word = word.substr(1);
|
||||
newLine = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
Result<std::string> file_utils::readString(std::string const& path) {
|
||||
Result<std::string> utils::file::readString(std::string const& path) {
|
||||
std::ifstream in(path, std::ios::in | std::ios::binary);
|
||||
if (in) {
|
||||
std::string contents;
|
||||
|
@ -18,7 +18,7 @@ Result<std::string> file_utils::readString(std::string const& path) {
|
|||
}
|
||||
|
||||
#if _WIN32
|
||||
Result<std::string> file_utils::readString(std::wstring const& path) {
|
||||
Result<std::string> utils::file::readString(std::wstring const& path) {
|
||||
std::ifstream in(path, std::ios::in | std::ios::binary);
|
||||
if (in) {
|
||||
std::string contents;
|
||||
|
@ -33,7 +33,7 @@ Result<std::string> file_utils::readString(std::wstring const& path) {
|
|||
}
|
||||
#endif
|
||||
|
||||
Result<std::string> file_utils::readString(ghc::filesystem::path const& path) {
|
||||
Result<std::string> utils::file::readString(ghc::filesystem::path const& path) {
|
||||
std::ifstream in(path.string(), std::ios::in | std::ios::binary);
|
||||
if (in) {
|
||||
std::string contents;
|
||||
|
@ -47,7 +47,7 @@ Result<std::string> file_utils::readString(ghc::filesystem::path const& path) {
|
|||
return Err("Unable to open file");
|
||||
}
|
||||
|
||||
Result<byte_array> file_utils::readBinary(std::string const& path) {
|
||||
Result<byte_array> utils::file::readBinary(std::string const& path) {
|
||||
std::ifstream in(path, std::ios::in | std::ios::binary);
|
||||
if (in) {
|
||||
return Ok(byte_array (std::istreambuf_iterator<char>(in), {}));
|
||||
|
@ -56,7 +56,7 @@ Result<byte_array> file_utils::readBinary(std::string const& path) {
|
|||
}
|
||||
|
||||
#if _WIN32
|
||||
Result<byte_array> file_utils::readBinary(std::wstring const& path) {
|
||||
Result<byte_array> utils::file::readBinary(std::wstring const& path) {
|
||||
std::ifstream in(path, std::ios::in | std::ios::binary);
|
||||
if (in) {
|
||||
return Ok(byte_array (std::istreambuf_iterator<char>(in), {}));
|
||||
|
@ -65,7 +65,7 @@ Result<byte_array> file_utils::readBinary(std::wstring const& path) {
|
|||
}
|
||||
#endif
|
||||
|
||||
Result<byte_array> file_utils::readBinary(ghc::filesystem::path const& path) {
|
||||
Result<byte_array> utils::file::readBinary(ghc::filesystem::path const& path) {
|
||||
std::ifstream in(path.string(), std::ios::in | std::ios::binary);
|
||||
if (in) {
|
||||
return Ok(byte_array (std::istreambuf_iterator<char>(in), {}));
|
||||
|
@ -73,7 +73,7 @@ Result<byte_array> file_utils::readBinary(ghc::filesystem::path const& path) {
|
|||
return Err("Unable to open file");
|
||||
}
|
||||
|
||||
Result<> file_utils::writeString(std::string const& path, std::string const& data) {
|
||||
Result<> utils::file::writeString(std::string const& path, std::string const& data) {
|
||||
std::ofstream file;
|
||||
file.open(path);
|
||||
if (file.is_open()) {
|
||||
|
@ -87,7 +87,7 @@ Result<> file_utils::writeString(std::string const& path, std::string const& dat
|
|||
}
|
||||
|
||||
#if _WIN32
|
||||
Result<> file_utils::writeString(std::wstring const& path, std::string const& data) {
|
||||
Result<> utils::file::writeString(std::wstring const& path, std::string const& data) {
|
||||
std::ofstream file;
|
||||
file.open(path);
|
||||
if (file.is_open()) {
|
||||
|
@ -101,7 +101,7 @@ Result<> file_utils::writeString(std::wstring const& path, std::string const& da
|
|||
}
|
||||
#endif
|
||||
|
||||
Result<> file_utils::writeString(ghc::filesystem::path const& path, std::string const& data) {
|
||||
Result<> utils::file::writeString(ghc::filesystem::path const& path, std::string const& data) {
|
||||
std::ofstream file;
|
||||
file.open(path.string());
|
||||
if (file.is_open()) {
|
||||
|
@ -114,7 +114,7 @@ Result<> file_utils::writeString(ghc::filesystem::path const& path, std::string
|
|||
return Err<>("Unable to open file");
|
||||
}
|
||||
|
||||
Result<> file_utils::writeBinary(std::string const& path, byte_array const& data) {
|
||||
Result<> utils::file::writeBinary(std::string const& path, byte_array const& data) {
|
||||
std::ofstream file;
|
||||
file.open(path, std::ios::out | std::ios::binary);
|
||||
if (file.is_open()) {
|
||||
|
@ -128,7 +128,7 @@ Result<> file_utils::writeBinary(std::string const& path, byte_array const& data
|
|||
}
|
||||
|
||||
#if _WIN32
|
||||
Result<> file_utils::writeBinary(std::wstring const& path, byte_array const& data) {
|
||||
Result<> utils::file::writeBinary(std::wstring const& path, byte_array const& data) {
|
||||
std::ofstream file;
|
||||
file.open(path, std::ios::out | std::ios::binary);
|
||||
if (file.is_open()) {
|
||||
|
@ -142,7 +142,7 @@ Result<> file_utils::writeBinary(std::wstring const& path, byte_array const& dat
|
|||
}
|
||||
#endif
|
||||
|
||||
Result<> file_utils::writeBinary(ghc::filesystem::path const& path, byte_array const& data) {
|
||||
Result<> utils::file::writeBinary(ghc::filesystem::path const& path, byte_array const& data) {
|
||||
std::ofstream file;
|
||||
file.open(path.string(), std::ios::out | std::ios::binary);
|
||||
if (file.is_open()) {
|
||||
|
@ -155,19 +155,19 @@ Result<> file_utils::writeBinary(ghc::filesystem::path const& path, byte_array c
|
|||
return Err<>("Unable to open file");
|
||||
}
|
||||
|
||||
Result<> file_utils::createDirectory(std::string const& path) {
|
||||
Result<> utils::file::createDirectory(std::string const& path) {
|
||||
if (ghc::filesystem::create_directory(path))
|
||||
return Ok<>();
|
||||
return Err<>("Unable to create directory");
|
||||
}
|
||||
|
||||
Result<> file_utils::createDirectoryAll(std::string const& path) {
|
||||
Result<> utils::file::createDirectoryAll(std::string const& path) {
|
||||
if (ghc::filesystem::create_directories(path))
|
||||
return Ok<>();
|
||||
return Err<>("Unable to create directories");
|
||||
}
|
||||
|
||||
Result<std::vector<std::string>> file_utils::listFiles(std::string const& path) {
|
||||
Result<std::vector<std::string>> utils::file::listFiles(std::string const& path) {
|
||||
if (!ghc::filesystem::exists(path))
|
||||
return Err<>("Directory does not exist");
|
||||
|
||||
|
@ -178,7 +178,7 @@ Result<std::vector<std::string>> file_utils::listFiles(std::string const& path)
|
|||
return Ok<>(res);
|
||||
}
|
||||
|
||||
Result<std::vector<std::string>> file_utils::listFilesRecursively(std::string const& path) {
|
||||
Result<std::vector<std::string>> utils::file::listFilesRecursively(std::string const& path) {
|
||||
if (!ghc::filesystem::exists(path))
|
||||
return Err<>("Directory does not exist");
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ std::string utils::clipboard::read() {
|
|||
return std::string([[UIPasteboard generalPasteboard].string UTF8String]);
|
||||
}
|
||||
|
||||
ghc::filesystem::path utils::dirs::geodeRoot() {
|
||||
ghc::filesystem::path utils::file::geodeRoot() {
|
||||
return ghc::filesystem::path([[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject].path.UTF8String);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,14 +21,14 @@ std::string utils::clipboard::read() {
|
|||
return std::string(clipboard);
|
||||
}
|
||||
|
||||
ghc::filesystem::path utils::dirs::geodeRoot() {
|
||||
ghc::filesystem::path utils::file::geodeRoot() {
|
||||
char cwd[PATH_MAX];
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
// utils::clipboard::write(cwd);
|
||||
return ghc::filesystem::path(cwd);
|
||||
}
|
||||
|
||||
bool utils::dirs::openFolder(ghc::filesystem::path const& path) {
|
||||
bool utils::file::openFolder(ghc::filesystem::path const& path) {
|
||||
NSURL* fileURL = [NSURL fileURLWithPath: [NSString stringWithUTF8String: path.string().c_str()]];
|
||||
NSURL* folderURL = [fileURL URLByDeletingLastPathComponent];
|
||||
[[NSWorkspace sharedWorkspace] openURL: folderURL];
|
||||
|
|
|
@ -9,14 +9,14 @@ USE_GEODE_NAMESPACE();
|
|||
#include <Windows.h>
|
||||
#include <stringapiset.h>
|
||||
|
||||
std::string string_utils::wideToUtf8(std::wstring const& wstr) {
|
||||
std::string utils::string::wideToUtf8(std::wstring const& wstr) {
|
||||
int count = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL);
|
||||
std::string str(count, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::wstring string_utils::utf8ToWide(std::string const& str) {
|
||||
std::wstring utils::string::utf8ToWide(std::string const& str) {
|
||||
int count = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
|
||||
std::wstring wstr(count, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstr[0], count);
|
||||
|
@ -25,22 +25,22 @@ std::wstring string_utils::utf8ToWide(std::string const& str) {
|
|||
|
||||
#endif
|
||||
|
||||
bool string_utils::startsWith(std::string const& str, std::string const& prefix) {
|
||||
bool utils::string::startsWith(std::string const& str, std::string const& prefix) {
|
||||
return str.rfind(prefix, 0) == 0;
|
||||
}
|
||||
bool string_utils::startsWith(std::wstring const& str, std::wstring const& prefix) {
|
||||
bool utils::string::startsWith(std::wstring const& str, std::wstring const& prefix) {
|
||||
return str.rfind(prefix, 0) == 0;
|
||||
}
|
||||
bool string_utils::endsWith(std::string const& str, std::string const& suffix) {
|
||||
bool utils::string::endsWith(std::string const& str, std::string const& suffix) {
|
||||
if (suffix.size() > str.size()) return false;
|
||||
return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
|
||||
}
|
||||
bool string_utils::endsWith(std::wstring const& str, std::wstring const& suffix) {
|
||||
bool utils::string::endsWith(std::wstring const& str, std::wstring const& suffix) {
|
||||
if (suffix.size() > str.size()) return false;
|
||||
return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
|
||||
}
|
||||
|
||||
std::string& string_utils::toLowerIP(std::string& str) {
|
||||
std::string& utils::string::toLowerIP(std::string& str) {
|
||||
std::transform(
|
||||
str.begin(), str.end(),
|
||||
str.begin(),
|
||||
|
@ -51,7 +51,7 @@ std::string& string_utils::toLowerIP(std::string& str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
std::wstring& string_utils::toLowerIP(std::wstring& str) {
|
||||
std::wstring& utils::string::toLowerIP(std::wstring& str) {
|
||||
std::transform(
|
||||
str.begin(), str.end(),
|
||||
str.begin(),
|
||||
|
@ -62,17 +62,17 @@ std::wstring& string_utils::toLowerIP(std::wstring& str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string string_utils::toLower(std::string const& str) {
|
||||
std::string utils::string::toLower(std::string const& str) {
|
||||
std::string ret = str;
|
||||
return string_utils::toLowerIP(ret);
|
||||
return utils::string::toLowerIP(ret);
|
||||
}
|
||||
|
||||
std::wstring string_utils::toLower(std::wstring const& str) {
|
||||
std::wstring utils::string::toLower(std::wstring const& str) {
|
||||
std::wstring ret = str;
|
||||
return string_utils::toLowerIP(ret);
|
||||
return utils::string::toLowerIP(ret);
|
||||
}
|
||||
|
||||
std::string& string_utils::toUpperIP(std::string& str) {
|
||||
std::string& utils::string::toUpperIP(std::string& str) {
|
||||
std::transform(
|
||||
str.begin(), str.end(),
|
||||
str.begin(),
|
||||
|
@ -83,7 +83,7 @@ std::string& string_utils::toUpperIP(std::string& str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
std::wstring& string_utils::toUpperIP(std::wstring& str) {
|
||||
std::wstring& utils::string::toUpperIP(std::wstring& str) {
|
||||
std::transform(
|
||||
str.begin(), str.end(),
|
||||
str.begin(),
|
||||
|
@ -94,17 +94,17 @@ std::wstring& string_utils::toUpperIP(std::wstring& str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string string_utils::toUpper(std::string const& str) {
|
||||
std::string utils::string::toUpper(std::string const& str) {
|
||||
std::string ret = str;
|
||||
return string_utils::toUpperIP(ret);
|
||||
return utils::string::toUpperIP(ret);
|
||||
}
|
||||
|
||||
std::wstring string_utils::toUpper(std::wstring const& str) {
|
||||
std::wstring utils::string::toUpper(std::wstring const& str) {
|
||||
std::wstring ret = str;
|
||||
return string_utils::toUpperIP(ret);
|
||||
return utils::string::toUpperIP(ret);
|
||||
}
|
||||
|
||||
std::string& string_utils::replaceIP(
|
||||
std::string& utils::string::replaceIP(
|
||||
std::string & str,
|
||||
std::string const& orig,
|
||||
std::string const& repl
|
||||
|
@ -117,7 +117,7 @@ std::string& string_utils::replaceIP(
|
|||
return str;
|
||||
}
|
||||
|
||||
std::wstring& string_utils::replaceIP(
|
||||
std::wstring& utils::string::replaceIP(
|
||||
std::wstring & str,
|
||||
std::wstring const& orig,
|
||||
std::wstring const& repl
|
||||
|
@ -130,25 +130,25 @@ std::wstring& string_utils::replaceIP(
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string string_utils::replace(
|
||||
std::string utils::string::replace(
|
||||
std::string const& str,
|
||||
std::string const& orig,
|
||||
std::string const& repl
|
||||
) {
|
||||
auto ret = str;
|
||||
return string_utils::replaceIP(ret, orig, repl);
|
||||
return utils::string::replaceIP(ret, orig, repl);
|
||||
}
|
||||
|
||||
std::wstring string_utils::replace(
|
||||
std::wstring utils::string::replace(
|
||||
std::wstring const& str,
|
||||
std::wstring const& orig,
|
||||
std::wstring const& repl
|
||||
) {
|
||||
auto ret = str;
|
||||
return string_utils::replaceIP(ret, orig, repl);
|
||||
return utils::string::replaceIP(ret, orig, repl);
|
||||
}
|
||||
|
||||
std::vector<std::string> string_utils::split(
|
||||
std::vector<std::string> utils::string::split(
|
||||
std::string const& str,
|
||||
std::string const& split
|
||||
) {
|
||||
|
@ -165,7 +165,7 @@ std::vector<std::string> string_utils::split(
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> string_utils::split(
|
||||
std::vector<std::wstring> utils::string::split(
|
||||
std::wstring const& str,
|
||||
std::wstring const& split
|
||||
) {
|
||||
|
@ -182,7 +182,7 @@ std::vector<std::wstring> string_utils::split(
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<char> string_utils::split(std::string const& str) {
|
||||
std::vector<char> utils::string::split(std::string const& str) {
|
||||
std::vector<char> res;
|
||||
for (auto const& s : str) {
|
||||
res.push_back(s);
|
||||
|
@ -190,7 +190,7 @@ std::vector<char> string_utils::split(std::string const& str) {
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<wchar_t> string_utils::split(std::wstring const& str) {
|
||||
std::vector<wchar_t> utils::string::split(std::wstring const& str) {
|
||||
std::vector<wchar_t> res;
|
||||
for (auto const& s : str) {
|
||||
res.push_back(s);
|
||||
|
@ -198,83 +198,83 @@ std::vector<wchar_t> string_utils::split(std::wstring const& str) {
|
|||
return res;
|
||||
}
|
||||
|
||||
bool string_utils::contains(std::string const& str, std::string const& subs) {
|
||||
bool utils::string::contains(std::string const& str, std::string const& subs) {
|
||||
return str.find(subs) != std::string::npos;
|
||||
}
|
||||
|
||||
bool string_utils::contains(std::wstring const& str, std::wstring const& subs) {
|
||||
bool utils::string::contains(std::wstring const& str, std::wstring const& subs) {
|
||||
return str.find(subs) != std::wstring::npos;
|
||||
}
|
||||
|
||||
bool string_utils::contains(std::string const& str, std::string::value_type c) {
|
||||
bool utils::string::contains(std::string const& str, std::string::value_type c) {
|
||||
return str.find(c) != std::string::npos;
|
||||
}
|
||||
|
||||
bool string_utils::contains(std::wstring const& str, std::wstring::value_type c) {
|
||||
bool utils::string::contains(std::wstring const& str, std::wstring::value_type c) {
|
||||
return str.find(c) != std::wstring::npos;
|
||||
}
|
||||
|
||||
bool string_utils::containsAny(
|
||||
bool utils::string::containsAny(
|
||||
std::string const& str,
|
||||
std::vector<std::string> const& subs
|
||||
) {
|
||||
for (auto const& sub : subs) {
|
||||
if (string_utils::contains(str, sub))
|
||||
if (utils::string::contains(str, sub))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool string_utils::containsAny(
|
||||
bool utils::string::containsAny(
|
||||
std::wstring const& str,
|
||||
std::vector<std::wstring> const& subs
|
||||
) {
|
||||
for (auto const& sub : subs) {
|
||||
if (string_utils::contains(str, sub))
|
||||
if (utils::string::contains(str, sub))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool string_utils::containsAll(
|
||||
bool utils::string::containsAll(
|
||||
std::string const& str,
|
||||
std::vector<std::string> const& subs
|
||||
) {
|
||||
bool found = true;
|
||||
for (auto const& sub : subs) {
|
||||
if (!string_utils::contains(str, sub))
|
||||
if (!utils::string::contains(str, sub))
|
||||
found = false;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool string_utils::containsAll(
|
||||
bool utils::string::containsAll(
|
||||
std::wstring const& str,
|
||||
std::vector<std::wstring> const& subs
|
||||
) {
|
||||
bool found = true;
|
||||
for (auto const& sub : subs) {
|
||||
if (!string_utils::contains(str, sub))
|
||||
if (!utils::string::contains(str, sub))
|
||||
found = false;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
size_t string_utils::count(std::string const& str, char countC) {
|
||||
size_t utils::string::count(std::string const& str, char countC) {
|
||||
size_t res = 0;
|
||||
for (auto c : str)
|
||||
if (c == countC) res++;
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t string_utils::count(std::wstring const& str, wchar_t countC) {
|
||||
size_t utils::string::count(std::wstring const& str, wchar_t countC) {
|
||||
size_t res = 0;
|
||||
for (auto c : str)
|
||||
if (c == countC) res++;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string& string_utils::trimLeftIP(std::string & str) {
|
||||
std::string& utils::string::trimLeftIP(std::string & str) {
|
||||
str.erase(str.begin(),
|
||||
std::find_if(str.begin(), str.end(), [](auto ch) {
|
||||
return !std::isspace(ch);
|
||||
|
@ -283,7 +283,7 @@ std::string& string_utils::trimLeftIP(std::string & str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
std::wstring& string_utils::trimLeftIP(std::wstring & str) {
|
||||
std::wstring& utils::string::trimLeftIP(std::wstring & str) {
|
||||
str.erase(str.begin(),
|
||||
std::find_if(str.begin(), str.end(), [](auto ch) {
|
||||
return !std::isspace(ch);
|
||||
|
@ -292,84 +292,84 @@ std::wstring& string_utils::trimLeftIP(std::wstring & str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string& string_utils::trimRightIP(std::string & str) {
|
||||
std::string& utils::string::trimRightIP(std::string & str) {
|
||||
str.erase(std::find_if(str.rbegin(), str.rend(), [](auto ch) {
|
||||
return !std::isspace(ch);
|
||||
}).base(), str.end());
|
||||
return str;
|
||||
}
|
||||
|
||||
std::wstring& string_utils::trimRightIP(std::wstring & str) {
|
||||
std::wstring& utils::string::trimRightIP(std::wstring & str) {
|
||||
str.erase(std::find_if(str.rbegin(), str.rend(), [](auto ch) {
|
||||
return !std::isspace(ch);
|
||||
}).base(), str.end());
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string& string_utils::trimIP(std::string & str) {
|
||||
std::string& utils::string::trimIP(std::string & str) {
|
||||
return
|
||||
string_utils::trimLeftIP(
|
||||
string_utils::trimRightIP(
|
||||
utils::string::trimLeftIP(
|
||||
utils::string::trimRightIP(
|
||||
str
|
||||
));
|
||||
}
|
||||
|
||||
std::wstring& string_utils::trimIP(std::wstring & str) {
|
||||
std::wstring& utils::string::trimIP(std::wstring & str) {
|
||||
return
|
||||
string_utils::trimLeftIP(
|
||||
string_utils::trimRightIP(
|
||||
utils::string::trimLeftIP(
|
||||
utils::string::trimRightIP(
|
||||
str
|
||||
));
|
||||
}
|
||||
|
||||
std::string string_utils::trimLeft(std::string const& str) {
|
||||
std::string utils::string::trimLeft(std::string const& str) {
|
||||
auto s2 = str;
|
||||
return string_utils::trimLeftIP(s2);
|
||||
return utils::string::trimLeftIP(s2);
|
||||
}
|
||||
|
||||
std::wstring string_utils::trimLeft(std::wstring const& str) {
|
||||
std::wstring utils::string::trimLeft(std::wstring const& str) {
|
||||
auto s2 = str;
|
||||
return string_utils::trimLeftIP(s2);
|
||||
return utils::string::trimLeftIP(s2);
|
||||
}
|
||||
|
||||
std::string string_utils::trimRight(std::string const& str) {
|
||||
std::string utils::string::trimRight(std::string const& str) {
|
||||
auto ret = str;
|
||||
return string_utils::trimRightIP(ret);
|
||||
return utils::string::trimRightIP(ret);
|
||||
}
|
||||
|
||||
std::wstring string_utils::trimRight(std::wstring const& str) {
|
||||
std::wstring utils::string::trimRight(std::wstring const& str) {
|
||||
auto ret = str;
|
||||
return string_utils::trimRightIP(ret);
|
||||
return utils::string::trimRightIP(ret);
|
||||
}
|
||||
|
||||
std::string string_utils::trim(std::string const& str) {
|
||||
std::string utils::string::trim(std::string const& str) {
|
||||
auto ret = str;
|
||||
return string_utils::trimIP(ret);
|
||||
return utils::string::trimIP(ret);
|
||||
}
|
||||
|
||||
std::wstring string_utils::trim(std::wstring const& str) {
|
||||
std::wstring utils::string::trim(std::wstring const& str) {
|
||||
auto ret = str;
|
||||
return string_utils::trimIP(ret);
|
||||
return utils::string::trimIP(ret);
|
||||
}
|
||||
|
||||
std::string& string_utils::normalizeIP(std::string & str) {
|
||||
while (string_utils::contains(str, " "))
|
||||
string_utils::replaceIP(str, " ", " ");
|
||||
std::string& utils::string::normalizeIP(std::string & str) {
|
||||
while (utils::string::contains(str, " "))
|
||||
utils::string::replaceIP(str, " ", " ");
|
||||
return str;
|
||||
}
|
||||
|
||||
std::wstring& string_utils::normalizeIP(std::wstring & str) {
|
||||
while (string_utils::contains(str, L" "))
|
||||
string_utils::replaceIP(str, L" ", L" ");
|
||||
std::wstring& utils::string::normalizeIP(std::wstring & str) {
|
||||
while (utils::string::contains(str, L" "))
|
||||
utils::string::replaceIP(str, L" ", L" ");
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string string_utils::normalize(std::string const& str) {
|
||||
std::string utils::string::normalize(std::string const& str) {
|
||||
auto ret = str;
|
||||
return string_utils::normalizeIP(ret);
|
||||
return utils::string::normalizeIP(ret);
|
||||
}
|
||||
|
||||
std::wstring string_utils::normalize(std::wstring const& str) {
|
||||
std::wstring utils::string::normalize(std::wstring const& str) {
|
||||
auto ret = str;
|
||||
return string_utils::normalizeIP(ret);
|
||||
return utils::string::normalizeIP(ret);
|
||||
}
|
||||
|
|
15
loader/src/utils/windows/NFD_LICENSE
Normal file
15
loader/src/utils/windows/NFD_LICENSE
Normal file
|
@ -0,0 +1,15 @@
|
|||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
281
loader/src/utils/windows/nfdwin.cpp
Normal file
281
loader/src/utils/windows/nfdwin.cpp
Normal file
|
@ -0,0 +1,281 @@
|
|||
#include "nfdwin.hpp"
|
||||
#include <Geode/utils/string.hpp>
|
||||
|
||||
#ifdef GEODE_IS_WINDOWS
|
||||
|
||||
using Path = ghc::filesystem::path;
|
||||
using Paths = std::vector<ghc::filesystem::path>;
|
||||
|
||||
static BOOL COMIsInitialized(HRESULT coResult) {
|
||||
if (coResult == RPC_E_CHANGED_MODE) {
|
||||
// If COM was previously initialized with different init flags,
|
||||
// NFD still needs to operate. Eat this warning.
|
||||
return true;
|
||||
}
|
||||
return SUCCEEDED(coResult);
|
||||
}
|
||||
|
||||
static HRESULT COMInit(void) {
|
||||
return CoInitializeEx(
|
||||
nullptr,
|
||||
COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE
|
||||
);
|
||||
}
|
||||
|
||||
static void COMUninit(HRESULT coResult) {
|
||||
// do not uninitialize if RPC_E_CHANGED_MODE occurred -- this
|
||||
// case does not refcount COM.
|
||||
if (SUCCEEDED(coResult)) {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
static std::pair<std::wstring, std::wstring> transformFilter(
|
||||
file::FilePickOptions::Filter const& filter
|
||||
) {
|
||||
std::wstring extensions {};
|
||||
bool first = true;
|
||||
for (auto& ext : filter.files) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
extensions += L";";
|
||||
}
|
||||
extensions += string::utf8ToWide(ext);
|
||||
}
|
||||
return {
|
||||
string::utf8ToWide(filter.description),
|
||||
extensions,
|
||||
};
|
||||
}
|
||||
|
||||
static bool addFiltersToDialog(
|
||||
::IFileDialog *dialog,
|
||||
std::vector<file::FilePickOptions::Filter> const& filters
|
||||
) {
|
||||
if (!filters.size()) {
|
||||
return true;
|
||||
}
|
||||
std::vector<std::pair<std::wstring, std::wstring>> wfilters {};
|
||||
wfilters.reserve(filters.size());
|
||||
std::transform(
|
||||
filters.begin(),
|
||||
filters.end(),
|
||||
std::back_inserter(wfilters),
|
||||
transformFilter
|
||||
);
|
||||
wfilters.push_back({ L"All Files", L"*.*" });
|
||||
std::vector<COMDLG_FILTERSPEC> specList {};
|
||||
specList.reserve(filters.size() + 1);
|
||||
for (auto& filter : wfilters) {
|
||||
specList.emplace_back(
|
||||
filter.first.c_str(),
|
||||
filter.second.c_str()
|
||||
);
|
||||
}
|
||||
return SUCCEEDED(
|
||||
dialog->SetFileTypes(specList.size(), specList.data())
|
||||
);
|
||||
}
|
||||
|
||||
static Result<Paths> convShellItems(IShellItemArray* shellItems) {
|
||||
DWORD shellItemCount;
|
||||
if (!SUCCEEDED(shellItems->GetCount(&shellItemCount))) {
|
||||
return Err("Unable to get shell item count");
|
||||
}
|
||||
|
||||
std::vector<ghc::filesystem::path> paths;
|
||||
for (DWORD i = 0; i < shellItemCount; i++) {
|
||||
IShellItem* shellItem;
|
||||
if (!SUCCEEDED(shellItems->GetItemAt(i, &shellItem))) {
|
||||
return Err("Unable to get shell item");
|
||||
}
|
||||
|
||||
SFGAOF attribs;
|
||||
if (!SUCCEEDED(shellItem->GetAttributes(SFGAO_FILESYSTEM, &attribs))) {
|
||||
return Err("Unable to get shell item attributes");
|
||||
}
|
||||
if (!(attribs & SFGAO_FILESYSTEM)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LPWSTR name;
|
||||
shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name);
|
||||
|
||||
paths.push_back(name);
|
||||
|
||||
CoTaskMemFree(name);
|
||||
}
|
||||
return Ok(paths);
|
||||
}
|
||||
|
||||
static bool setDefaultPath(
|
||||
IFileDialog* dialog,
|
||||
ghc::filesystem::path const& defaultPath
|
||||
) {
|
||||
IShellItem* folder;
|
||||
if (!SUCCEEDED(SHCreateItemFromParsingName(
|
||||
defaultPath.wstring().c_str(), nullptr,
|
||||
IID_PPV_ARGS(&folder)
|
||||
))) {
|
||||
return false;
|
||||
}
|
||||
dialog->SetFolder(folder);
|
||||
folder->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct Holder {
|
||||
T m_deallocator;
|
||||
Holder(T&& deallocator) : m_deallocator(deallocator) {}
|
||||
~Holder() {
|
||||
m_deallocator();
|
||||
}
|
||||
};
|
||||
|
||||
Result<> nfdPick(
|
||||
NFDMode mode,
|
||||
file::FilePickOptions const& options,
|
||||
void* result
|
||||
) {
|
||||
auto coResult = COMInit();
|
||||
if (!COMIsInitialized(coResult)) {
|
||||
return Err("Could not initialize COM");
|
||||
}
|
||||
|
||||
auto clsid = (
|
||||
mode == NFDMode::SaveFile ?
|
||||
CLSID_FileSaveDialog :
|
||||
CLSID_FileOpenDialog
|
||||
);
|
||||
auto iid = (
|
||||
mode == NFDMode::SaveFile ?
|
||||
IID_IFileSaveDialog :
|
||||
IID_IFileOpenDialog
|
||||
);
|
||||
|
||||
IFileDialog* dialog = nullptr;
|
||||
Holder _([&]() {
|
||||
if (dialog) {
|
||||
dialog->Release();
|
||||
}
|
||||
COMUninit(coResult);
|
||||
});
|
||||
|
||||
if (!SUCCEEDED(CoCreateInstance(
|
||||
clsid, nullptr, CLSCTX_ALL, iid,
|
||||
reinterpret_cast<void**>(&dialog)
|
||||
))) {
|
||||
return Err("Could not create dialog");
|
||||
}
|
||||
|
||||
if (!addFiltersToDialog(dialog, options.filters)) {
|
||||
return Err("Unable to add filters to dialog");
|
||||
}
|
||||
if (!setDefaultPath(dialog, options.defaultPath)) {
|
||||
return Err("Unable to set default path to dialog");
|
||||
}
|
||||
|
||||
if (mode == NFDMode::OpenFiles) {
|
||||
DWORD flags;
|
||||
if (!SUCCEEDED(dialog->GetOptions(&flags))) {
|
||||
return Err("Unable to get dialog options");
|
||||
}
|
||||
if (!SUCCEEDED(
|
||||
dialog->SetOptions(flags | FOS_ALLOWMULTISELECT)
|
||||
)) {
|
||||
return Err("Unable to set dialog options");
|
||||
}
|
||||
}
|
||||
else if (mode == NFDMode::OpenFolder) {
|
||||
DWORD flags;
|
||||
if (!SUCCEEDED(dialog->GetOptions(&flags))) {
|
||||
return Err("Unable to get dialog options");
|
||||
}
|
||||
if (!SUCCEEDED(
|
||||
dialog->SetOptions(flags | FOS_PICKFOLDERS)
|
||||
)) {
|
||||
return Err("Unable to set dialog options");
|
||||
}
|
||||
}
|
||||
|
||||
switch (dialog->Show(nullptr)) {
|
||||
case S_OK: {
|
||||
switch (mode) {
|
||||
case NFDMode::OpenFile:
|
||||
case NFDMode::SaveFile: {
|
||||
IShellItem* shellItem = nullptr;
|
||||
if (!SUCCEEDED(dialog->GetResult(&shellItem))) {
|
||||
return Err("Could not get result from dialog");
|
||||
}
|
||||
Holder _([&]() {
|
||||
shellItem->Release();
|
||||
});
|
||||
|
||||
wchar_t* filePath = nullptr;
|
||||
if (!SUCCEEDED(
|
||||
shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)
|
||||
)) {
|
||||
return Err("Could not get path from result");
|
||||
}
|
||||
|
||||
*reinterpret_cast<Path*>(result) = filePath;
|
||||
CoTaskMemFree(filePath);
|
||||
|
||||
return Ok();
|
||||
} break;
|
||||
|
||||
case NFDMode::OpenFiles: {
|
||||
IShellItemArray *shellItems;
|
||||
if (!SUCCEEDED(static_cast<IFileOpenDialog*>(
|
||||
dialog
|
||||
)->GetResults(&shellItems))) {
|
||||
return Err("Could not get results from dialog");
|
||||
}
|
||||
Holder _([&]() {
|
||||
shellItems->Release();
|
||||
});
|
||||
auto res = convShellItems(shellItems);
|
||||
if (!res) {
|
||||
return Err(res.error());
|
||||
}
|
||||
*reinterpret_cast<Paths*>(result) = res.value();
|
||||
return Ok();
|
||||
} break;
|
||||
|
||||
case NFDMode::OpenFolder: {
|
||||
IShellItem* shellItem = nullptr;
|
||||
if (!SUCCEEDED(dialog->GetResult(&shellItem))) {
|
||||
return Err("Could not get result from dialog");
|
||||
}
|
||||
Holder _([&]() {
|
||||
shellItem->Release();
|
||||
});
|
||||
|
||||
wchar_t* filePath = nullptr;
|
||||
if (!SUCCEEDED(
|
||||
shellItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &filePath)
|
||||
)) {
|
||||
return Err("Could not get path from result");
|
||||
}
|
||||
|
||||
*reinterpret_cast<Path*>(result) = filePath;
|
||||
CoTaskMemFree(filePath);
|
||||
|
||||
return Ok();
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case HRESULT_FROM_WIN32(ERROR_CANCELLED): {
|
||||
return Err("Dialog cancelled");
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return Err("Unknown error");
|
||||
}
|
||||
|
||||
#endif
|
62
loader/src/utils/windows/nfdwin.hpp
Normal file
62
loader/src/utils/windows/nfdwin.hpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Native File Dialog
|
||||
http://www.frogtoss.com/labs
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copied from https://github.com/mlabbe/nativefiledialog
|
||||
* Modified to be modern Geode-fitting C++
|
||||
*/
|
||||
|
||||
#include <Geode/utils/platform.hpp>
|
||||
|
||||
#ifdef GEODE_IS_WINDOWS
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// Explicitly setting NTDDI version, this is necessary for the MinGW compiler
|
||||
#define NTDDI_VERSION NTDDI_VISTA
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#endif
|
||||
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
|
||||
/* only locally define UNICODE in this compilation unit */
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
#include <shobjidl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NFD_MAX_STRLEN 256
|
||||
#define _NFD_UNUSED(x) ((void)x)
|
||||
|
||||
#define NFD_UTF8_BOM "\xEF\xBB\xBF"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
enum class NFDMode {
|
||||
OpenFile,
|
||||
OpenFiles,
|
||||
SaveFile,
|
||||
OpenFolder,
|
||||
};
|
||||
|
||||
Result<> nfdPick(
|
||||
NFDMode mode,
|
||||
file::FilePickOptions const& options,
|
||||
void* result
|
||||
);
|
||||
|
||||
#endif
|
|
@ -8,6 +8,9 @@ USE_GEODE_NAMESPACE();
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <Windows.h>
|
||||
#include <shobjidl.h>
|
||||
#include <shlwapi.h>
|
||||
#include "nfdwin.hpp"
|
||||
|
||||
bool utils::clipboard::write(std::string const& data) {
|
||||
if (!OpenClipboard(nullptr))
|
||||
|
@ -67,16 +70,49 @@ std::string utils::clipboard::read() {
|
|||
return text;
|
||||
}
|
||||
|
||||
ghc::filesystem::path utils::dirs::geodeRoot() {
|
||||
ghc::filesystem::path utils::file::geodeRoot() {
|
||||
return ghc::filesystem::path(CCFileUtils::sharedFileUtils()->getWritablePath2().c_str());
|
||||
}
|
||||
|
||||
bool utils::dirs::openFolder(ghc::filesystem::path const& path) {
|
||||
bool utils::file::openFolder(ghc::filesystem::path const& path) {
|
||||
ShellExecuteA(NULL, "open", path.string().c_str(), NULL, NULL, SW_SHOWDEFAULT);
|
||||
return true;
|
||||
}
|
||||
|
||||
void geode::utils::web::openLinkInBrowser(std::string const& url) {
|
||||
Result<ghc::filesystem::path> utils::file::pickFile(
|
||||
file::PickMode mode,
|
||||
file::FilePickOptions const& options
|
||||
) {
|
||||
#define TURN_INTO_NFDMODE(mode) \
|
||||
case file::PickMode::mode: nfdMode = NFDMode::mode; break;
|
||||
|
||||
NFDMode nfdMode;
|
||||
switch (mode) {
|
||||
TURN_INTO_NFDMODE(OpenFile);
|
||||
TURN_INTO_NFDMODE(SaveFile);
|
||||
TURN_INTO_NFDMODE(OpenFolder);
|
||||
default: return Err("Unknown open mode");
|
||||
}
|
||||
ghc::filesystem::path path;
|
||||
auto r = nfdPick(nfdMode, options, &path);
|
||||
if (!r) {
|
||||
return Err(r.error());
|
||||
}
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
Result<std::vector<ghc::filesystem::path>> utils::file::pickFiles(
|
||||
file::FilePickOptions const& options
|
||||
) {
|
||||
std::vector<ghc::filesystem::path> paths;
|
||||
auto r = nfdPick(NFDMode::OpenFolder, options, &paths);
|
||||
if (!r) {
|
||||
return Err(r.error());
|
||||
}
|
||||
return Ok(paths);
|
||||
}
|
||||
|
||||
void utils::web::openLinkInBrowser(std::string const& url) {
|
||||
ShellExecuteA(0, 0, url.c_str(), 0, 0, SW_SHOW);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,16 +55,28 @@
|
|||
},
|
||||
"territory-battle": {
|
||||
"type": "color",
|
||||
"default": "#00f"
|
||||
"default": "#ff006f"
|
||||
},
|
||||
"faithful-dog-hachi": {
|
||||
"type": "rgba",
|
||||
"default": [ 255, 150, 55, 180 ]
|
||||
"default": [ 55, 224, 255, 255 ]
|
||||
},
|
||||
"im-getting-to-the-bus-to-the-other-world-see-ya": {
|
||||
"type": "file",
|
||||
"name": "Bus",
|
||||
"default": ""
|
||||
"default": "",
|
||||
"control": {
|
||||
"filters": [
|
||||
{
|
||||
"description": "Level Files",
|
||||
"files": [ "*.gmd2", "*.gmd", "*.lvl" ]
|
||||
},
|
||||
{
|
||||
"description": "GMD Files",
|
||||
"files": [ "*.gmd" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue