API — ICoreBlocks/ICoreServices
The public contract of 9 header(s) under src/ICoreBlocks/ICoreServices — 16 class/struct definition(s), 92 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.
ICoreLogger.h#
src/ICoreBlocks/ICoreServices/ICoreLogger.h
ICoreLogger#
ICoreLogger.h:9 · class · 7 declaration(s)
class ICoreLogger {
public:
static long initializeLoggers();
static void log(const std::string& logText);
static void logError(const std::string& logText);
static ICoreLoggerTextBox* createMainLogUI();
static void logCommandHistory(const std::string &logText);
static void logCommandHistoryError(const std::string &logText);
static ICoreLoggerTextBox* createNewCommandHistoryUI();
};
};
ICoreLoggerObject.h#
src/ICoreBlocks/ICoreServices/ICoreLoggerObject.h
ICoreLoggerObject -- one log stream: a file, the tail of that file kept in memory, and the set of sinks watching it.
This class is deliberately Qt-free. It used to inherit QObject solely to own a QTimer, and it used to create and feed ICoreLoggerTextBox widgets itself. Both are gone: the flush heartbeat is a std::thread, and views attach themselves through ICoreLogSink. That is what lets the stream run in a console build with no event loop and no widgets, and it keeps the decision about how a line LOOKS on the view's side of the seam.
ICoreLogSink#
ICoreLoggerObject.h:27 · class · 2 declaration(s)
A destination for log lines, implemented by anything that wants to watch a stream (today only ICoreLoggerTextBox).
class ICoreLogSink {
public:
virtual ~ICoreLogSink() = default;
virtual void onLogLine(const std::string& line) = 0;
};
};
ICoreLoggerObject#
ICoreLoggerObject.h:34 · class · pImpl · 8 declaration(s)
class ICoreLoggerObject {
public:
// `fileLoggingEnabled` is consulted at flush time rather than log time, so
// the preference can change mid-run. It is injected instead of read
// directly because the preferences header pulls in Qt, which would undo
// the point of this file. Omitting it means "always write".
explicit ICoreLoggerObject(const std::string& logFilePath,
std::function<bool()> fileLoggingEnabled = {});
~ICoreLoggerObject();
ICoreLoggerObject(const ICoreLoggerObject&) = delete;
ICoreLoggerObject& operator=(const ICoreLoggerObject&) = delete;
void log(const std::string& prefix, const std::string& message);
void logError(const std::string& prefix, const std::string& message);
// Replays the retained history into `sink` and then registers it, both
// under the caller's thread, so a line logged in between can neither be
// missed nor delivered twice.
void attachSink(ICoreLogSink* sink);
void detachSink(ICoreLogSink* sink);
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreProductInfo.h#
src/ICoreBlocks/ICoreServices/ICoreProductInfo.h
ICoreProductInfo#
ICoreProductInfo.h:37 · class · 17 declaration(s)
ICoreProductInfo What this build IS: the product's name, its version, and the commit it came from.
class ICoreProductInfo {
public:
// ---- Identity -------------------------------------------------------
// "ICore Blocks". The app's home folder under Documents is named after
// this (ICoreDocumentsFolder), so changing it moves every user's projects.
static std::string productName();
// "com.icore.blocks" -- the macOS bundle identifier, and the same string
// CMakeLists.txt gives the bundle. Kept here so nothing has to re-derive it.
static std::string bundleIdentifier();
// "macos-arm64", "windows-x64", "linux-x64" -- what KIND of build this is.
//
// ONE STRING, THREE PLACES. It names the redistributable artifact
// (ICoreBlocks-1.0.0-macos-arm64.dmg), it is the value the updater sends
// as ?platform=, and it is what releases.platform is keyed on in the
// licensing schema. Computed once in CMakeLists.txt and carried here by
// the build stamp, so no half of that can recompute it and drift: a build
// whose file name disagrees with the row describing it serves the wrong
// architecture to somebody, and each half looks correct on its own.
//
// Empty on a build configured before this existed, which is the same
// shippable-empty state every other stamp field has.
static std::string platformTag();
// ---- Version --------------------------------------------------------
// "1.0.0".
static std::string version();
static int versionMajor();
static int versionMinor();
static int versionPatch();
// "ICore Blocks 1.0.0". What AppInfo::getAppNameAndVersion() used to give.
static std::string nameAndVersion();
// ---- Build stamp ----------------------------------------------------
//
// Every one of these can legitimately be EMPTY: a tarball export, a shallow
// clone or a machine without git produces a build with no git facts at all.
// That is a real build and it must still run, so nothing here is allowed to
// be load-bearing -- callers print what they get and never parse it.
// The full 40-character commit, or empty.
static std::string commit();
// The abbreviated commit, or empty. Carries no "-dirty" suffix; ask
// isWorkingTreeDirty() for that, so the two facts stay separable.
static std::string commitShort();
// The branch the build was made on, or empty (a detached HEAD gives "HEAD").
static std::string branch();
// True when the working tree had uncommitted changes at build time. Such a
// build is NOT reproducible from its commit, and a stamp that hides it
// sends people to read source that was never what shipped.
static bool isWorkingTreeDirty();
// ISO-8601 UTC, e.g. "2026-08-18T14:03:11Z".
static std::string buildDate();
// "Release", "Debug", "RelWithDebInfo" -- or empty for a single-config
// generator configured with no CMAKE_BUILD_TYPE.
static std::string buildType();
// "AppleClang 17.0.0" -- compiler id and version, as CMake saw it.
static std::string compiler();
// ---- Composed ------------------------------------------------------
// One line, for a bug report or an About box:
// "1.0.0 (6cffc4d4-dirty, RelWithDebInfo, built 2026-08-18T14:03:11Z)"
// Degrades cleanly: the parts that are unknown are left out rather than
// printed empty.
static std::string buildStamp();
// The multi-line block `--version` prints. Product name, version, build
// stamp, and the toolkit version underneath.
static std::string versionBanner();
// All-static, stateless, no Impl -- there is nothing to construct. The
// definitions are generated (see the note above), not written here.
};
};
ICoreRunDiagnosis.h#
src/ICoreBlocks/ICoreServices/ICoreRunDiagnosis.h
ICoreRunDiagnosis#
ICoreRunDiagnosis.h:7 · class · 6 declaration(s)
class ICoreRunDiagnosis {
public:
static void log(const std::string& message);
static void logWarning(const std::string& message);
static void logError(const double &message);
static void logError(const std::string& message);
static void tryCatchingException();
static bool exceptionCaught();
};
};
ICoreRunningCopies.h#
src/ICoreBlocks/ICoreServices/ICoreRunningCopies.h
ICoreRunningCopies#
ICoreRunningCopies.h:25 · class · final · 2 declaration(s)
ICoreRunningCopies Which other copies of the app are running for this user, asked of the operating system rather than of a list somebody has to keep tidy.
class ICoreRunningCopies final {
public:
// Takes this process's entry under `appDataFolder`. Idempotent; a second
// call with another folder is ignored.
static void registerThisCopy(const std::filesystem::path& appDataFolder);
// Process ids of the OTHER copies running now. Empty when this copy has not
// registered (there is no folder to look in) or is the only one.
[[nodiscard]] static std::vector<std::int64_t> others();
};
ICoreSharedFile.h#
src/ICoreBlocks/ICoreServices/ICoreSharedFile.h
ICoreSharedFile#
ICoreSharedFile.h:45 · class · final · 2 declaration(s)
ICoreSharedFile How a file that SEVERAL COPIES OF THE APP write is changed without one copy undoing another, and how any file this app owns is replaced without ever being half written.
class ICoreSharedFile final {
public:
// How long a change waits for another copy to finish its own. Every change
// under these locks is a read and a small write, milliseconds long, so a
// wait this long means the other copy is stuck, not busy.
static constexpr int kLockTimeoutMs = 3000;
// Runs `body` holding the cross-process lock for `file`. False -- and
// `body` never ran -- when the lock could not be taken.
static bool withLock(const std::filesystem::path& file, const std::function<void()>& body,
std::string* error = nullptr);
// Read-modify-write of a whole file under its lock: `edit` receives the
// bytes on disk now (empty when the file does not exist) and returns the
// bytes to write. Returning exactly what it was given writes nothing.
static bool update(const std::filesystem::path& file,
const std::function<std::string(const std::string& current)>& edit,
std::string* error = nullptr);
// The same for an ini file through ICoreSettings: `edit` gets the file as it
// is on disk now and changes what it means to; every key it does not touch
// -- including ones another copy wrote since this one started -- is kept.
static bool updateSettings(const std::filesystem::path& file,
const std::function<void(ICoreSettings&)>& edit,
std::string* error = nullptr);
// Replaces `target` with `bytes` atomically, retrying a rename a virus
// scanner or a sync client is briefly holding up. NO LOCK: for a file only
// this process writes, or inside withLock(). True only when the target now
// holds exactly `bytes`; on false it is untouched.
static bool writeAtomically(const std::filesystem::path& target, const std::string& bytes,
std::string* error = nullptr);
// The whole file. False when it could not be read; a missing file is false.
static bool readAll(const std::filesystem::path& source, std::string& bytes);
// <dir>/.locks/<name>.lock
[[nodiscard]] static std::filesystem::path lockPathFor(const std::filesystem::path& file);
};
ICoreStaticCommands.h#
src/ICoreBlocks/ICoreServices/ICoreStaticCommands.h
ICoreStaticCommands#
ICoreStaticCommands.h:13 · class · 16 declaration(s)
Qt-free by design: the helpers that name a Qt GUI type (QFont/QColor serialization, the QGraphicsObject mouse-ungrab) live in ICoreStudio/Registry/ICoreStudioStaticCommands.h, so the block library ...
class ICoreStaticCommands {
public:
static bool startsWith(const std::string& str, const std::string& prefix);
static bool endsWith(const std::string& str, const std::string& suffix);
static bool contains(const std::string& str, const std::string& suffix);
static std::string removePrefixFromStart(const std::string& str, const std::string& prefix);
// Helper function to trim leading and trailing '/'
static std::string trimStartEndSlashes(const std::string& path);
static std::vector<std::string> splitBySlashes(const std::string& input);
// ===== Escaped-delimiter (de)serialization =====
// Serialization formats join fields with a single-char delimiter (e.g. '~'). A free-form
// field (such as a user-typed description) may itself contain that delimiter, which would
// otherwise split into the wrong number of fields and corrupt parsing. escapeForDelimiter()
// backslash-escapes the delimiter (and the backslash itself) on encode; splitEscaped()
// splits only on UN-escaped delimiters and unescapes each token on decode. Used together
// they let any field content round-trip safely. The pair is symmetric: a field encoded with
// escapeForDelimiter(field, d) is recovered exactly by splitEscaped(joined, d).
static std::string escapeForDelimiter(const std::string& field, char delimiter);
static std::vector<std::string> splitEscaped(const std::string& input, char delimiter);
static std::pair<std::string, std::string> splitByLastSlash(const std::string& input);
static std::string getParentPath(const std::string& path);
static bool validReturnMessage(const std::string& message);
// Greatest Common Divisor (GCD)
static long long gcd_vector(const std::vector<long long>& nums);
// Least Common Multiple (LCM)
static long long lcm_two(long long a, long long b);
static long long lcm_vector(const std::vector<long long>& nums);
static bool isValidPath(const std::string& str, std::filesystem::path& outPath);
static bool containsExactlyOnce(const std::string& mainStr,
const std::string& target);
static bool replaceExactlyOnce(std::string& mainStr,
const std::string& target,
const std::string& replacement);
static bool replaceAll(std::string& mainStr,
const std::string& target,
const std::string& replacement);
static std::string capitalizeFirst(std::string str);
// static std::string sanitizeIdentifier(const std::string& raw)
// {
// std::string out;
// out.reserve(raw.size());
//
// bool lastWasUnderscore = false;
// for (const char c : raw) {
// const unsigned char uc = static_cast<unsigned char>(c);
// if (std::isalnum(uc)) {
// out.push_back(c);
// lastWasUnderscore = false;
// } else {
// // Any space / separator / special char -> single underscore,
// // collapsing consecutive runs.
// if (!lastWasUnderscore) {
// out.push_back('_');
// lastWasUnderscore = true;
// }
// }
// }
//
// // Trim leading/trailing underscores.
// const std::size_t b = out.find_first_not_of('_');
// if (b == std::string::npos) {
// out.clear();
// } else {
// const std::size_t e = out.find_last_not_of('_');
// out = out.substr(b, e - b + 1);
// }
//
// // Must not be empty and must not start with a digit.
// if (out.empty() || std::isdigit(static_cast<unsigned char>(out.front()))) {
// out.insert(out.begin(), '_');
// }
//
// return out;
// }
};
};
ICoreToolchains.h#
src/ICoreBlocks/ICoreServices/ICoreToolchains.h
ICoreToolRequirement#
ICoreToolchains.h:77 · struct · 0 declaration(s)
struct ICoreToolRequirement {
public:
std::string name; // "numpy", "host architecture", "matiec library folder"
std::string neededFor; // "Python export verification"
bool satisfied = false;
std::string detail; // what the probe saw: "numpy 2.1.3", "x86_64-apple-darwin"
std::string fixHint; // one line the user can copy: "\"/usr/bin/python3\" -m pip install numpy"
};
};
ICoreToolCandidate#
ICoreToolchains.h:85 · struct · 0 declaration(s)
struct ICoreToolCandidate {
public:
std::filesystem::path path; // absolute; empty when Missing
std::string version; // "3.12.4", "clang 17.0.0"; may be empty
ICoreToolSource source = ICoreToolSource::None;
std::string sourceDetail; // "JAVA_HOME", "your shell's PATH", "/Library/Java/JavaVirtualMachines"
ICoreToolStatus status = ICoreToolStatus::Missing;
std::string detail; // why it is Rejected / Missing, for the user
std::vector<ICoreToolRequirement> requirements;
std::map<std::string, std::filesystem::path> siblings; // "java", "vvp", "lib"
};
};
ICoreToolResolution#
ICoreToolchains.h:96 · struct · bases ICoreToolCandidate · 1 declaration(s)
struct ICoreToolResolution : ICoreToolCandidate {
public:
bool pinned = false; // the user chose it (vs auto-detect)
std::filesystem::path pinnedPath; // what the user chose, kept even when it vanished
};
};
ICoreToolInfo#
ICoreToolchains.h:102 · struct · 0 declaration(s)
What the panel prints about a tool.
struct ICoreToolInfo {
public:
ICoreToolId id = ICoreToolId::Python;
std::string key; // "python" -- the ini group and the console id
std::string displayName; // "Python"
std::string section; // "Languages", "Hardware & PLC", "Math", "Source control"
std::string description; // one sentence: what the app uses it for
std::string installHint; // where to get it, one line
};
};
ICoreToolUse#
ICoreToolchains.h:119 · class · 1 declaration(s)
A consumer declares, beside its own code, that it runs a tool: static const ICoreToolUse gitUse(ICoreToolId::Git, "Git panel"); ICoreToolchains::usedBy() lists what was declared, so the Toolchains ...
class ICoreToolUse {
public:
ICoreToolUse(ICoreToolId id, const char* consumer);
};
};
ICoreToolchainsNotifier#
ICoreToolchains.h:124 · class · final · 0 declaration(s)
class ICoreToolchainsNotifier final {
public:
// A tool's answer changed: a pin, an unpin, or a rescan finished for it.
ICoreSignal<ICoreToolId> onToolChanged;
// A rescan() or warmUp() pass finished for every tool it covered.
ICoreSignal<> onScanFinished;
};
};
ICoreToolchains#
ICoreToolchains.h:132 · class · 27 declaration(s)
class ICoreToolchains {
public:
ICoreToolchains() = delete;
// Every tool the registry knows, in the order the panel lists them.
[[nodiscard]] static const std::vector<ICoreToolId>& allTools();
[[nodiscard]] static const ICoreToolInfo& info(ICoreToolId id);
// Every consumer that declared an ICoreToolUse for this tool, sorted.
[[nodiscard]] static std::vector<std::string> usedBy(ICoreToolId id);
// "python", "cc", "cxx", "rust", "jdk", "matlab", "ghdl", "iverilog", "matiec", "git".
[[nodiscard]] static std::string_view idName(ICoreToolId id);
[[nodiscard]] static std::optional<ICoreToolId> fromName(std::string_view name);
// The answer the application uses. Cheap once the tool has been scanned.
[[nodiscard]] static ICoreToolResolution resolve(ICoreToolId id);
// Every installation auto-detect found, ranked -- what the panel's combo lists.
// Does not include a pinned file that auto-detect would not have found.
[[nodiscard]] static std::vector<ICoreToolCandidate> candidates(ICoreToolId id);
// True once both resolve() and candidates() can answer from the cache --
// the test a UI thread makes before asking either, so it never probes.
// False from start until the first scan, and again after a pin/unpin.
[[nodiscard]] static bool isScanned(ICoreToolId id);
// A rescan() / warmUp() of this tool is running on the pool.
[[nodiscard]] static bool isScanning(ICoreToolId id);
// The file the user pinned, if any -- read from the stored choice, never
// probed. For a caller that only honours an explicit choice and must not
// start processes to find out (the agent bridge, writing a project's guides).
[[nodiscard]] static std::optional<std::filesystem::path> pinnedPath(ICoreToolId id);
// Choose a file / go back to auto-detect. Both persist immediately, drop
// the tool's cached answer, and fire onToolChanged. The next resolve()
// probes the new choice.
static void pin(ICoreToolId id, const std::filesystem::path& path);
static void unpin(ICoreToolId id);
// Re-probe one tool, or all of them: on the pool, returning at once --
// or, with `wait`, on the caller's thread, returning when it is done (the
// console, whose process exits right after the command).
static void rescan(std::optional<ICoreToolId> only = {}, bool wait = false);
// rescan() for every tool that has not been scanned yet. Called once at
// startup so the first export or panel opening finds a warm cache.
static void warmUp();
// Probe one file as the given tool, without changing any choice -- the
// panel's Test button and the console's `toolchain set` preview. Blocks.
[[nodiscard]] static ICoreToolCandidate test(ICoreToolId as, const std::filesystem::path& path);
// The quoted command for a shell line ("\"/path with space/rustc\""), or
// "" when the tool resolves to nothing usable (Missing / StalePin / Rejected).
[[nodiscard]] static std::string commandFor(ICoreToolId id);
// The directories searched for tools, in order: the user's login-shell
// PATH (read once, macOS/Linux), this process's PATH, then the fixed
// fallbacks a GUI app's PATH omits. On Windows only this process's PATH:
// what is installed off it (MSVC, MSYS2, the py launcher's Pythons, Git for
// Windows) is found by each tool's own well-known candidates instead.
[[nodiscard]] static std::vector<std::filesystem::path> searchPath();
// What a child process needs to run this tool: PATH = searchPath() with
// the tool's own folder in front, plus the tool's extras (the MSYS2 bin
// folder for GHDL / Icarus on Windows; INCLUDE and LIB for MSVC's cl.exe,
// derived from where it is installed). Pass to ICoreProcess::setEnvironment.
[[nodiscard]] static ICoreProcessEnvironment environmentFor(ICoreToolId id);
// The same environment as a prefix for a SHELL command line, for the
// callers that build one (the export verifier runs `popen`):
// POSIX: PATH="<dirs>" <command...>
// Windows: set "PATH=<dirs>;%PATH%" && [set "INCLUDE=..." && set "LIB=..." && ]<command...>
// Empty when the tool needs nothing beyond the inherited environment.
[[nodiscard]] static std::string shellPrefixFor(ICoreToolId id);
// The prefix for one particular file rather than the registry's answer --
// an export target's own compiler path. Quotes around it are ignored.
[[nodiscard]] static std::string shellPrefixFor(ICoreToolId id, const std::filesystem::path& file);
// True for Microsoft's cl.exe, whose command-line grammar is not gcc's
// (/Fe: for -o, /I for -I, no -lm). The C and C++ entries may hold either,
// so a consumer that builds a command line asks before building it.
[[nodiscard]] static bool isMsvcCompiler(const std::filesystem::path& compiler);
// Where the choices are stored, and an override for tests / headless runs
// with a scratch folder. Setting it drops every cached answer.
[[nodiscard]] static std::filesystem::path storageFile();
static void setStorageFolder(const std::filesystem::path& folder);
[[nodiscard]] static ICoreToolchainsNotifier& notifier();
// Human text for the enums, for the panel and the console.
[[nodiscard]] static std::string statusText(ICoreToolStatus status);
[[nodiscard]] static std::string sourceText(ICoreToolSource source);
};
};
File-scope declarations#
// ICoreToolchains -- the ONE place that decides which external program the
// application runs: Python, the C and C++ compilers, rustc, the JDK, MATLAB,
// GHDL, Icarus Verilog, matiec and git.
//
// Every consumer asks here instead of hunting for its own tool -- the export
// verifier, codegen's verification gate, the C Code block, the Git panel, the
enum class ICoreToolId {
Python,
CCompiler,
CxxCompiler,
Rust,
Jdk,
Matlab,
Ghdl,
IcarusVerilog,
Matiec,
Git
};
// Where a candidate came from, in ranking order.
enum class ICoreToolSource { Pinned, Environment, SearchPath, WellKnownDir, Bundled, None };
enum class ICoreToolStatus {
Ok, // runs, and meets every requirement
Missing, // nothing found (auto), or nothing chosen
Rejected, // found, but cannot be used at all (e.g. wrong architecture, does not run)
RequirementMissing, // runs, but a requirement some feature needs is not met (e.g. numpy)
StalePin // the pinned file no longer exists
};
ICoreWebFeatures.h#
src/ICoreBlocks/ICoreServices/ICoreWebFeatures.h
ICoreWebFeatures#
ICoreWebFeatures.h:28 · class · 3 declaration(s)
class ICoreWebFeatures {
public:
ICoreWebFeatures() = delete;
// False only where the application runs in a browser.
[[nodiscard]] static bool available(ICoreWebFeature feature);
// Why it is not here, for the user: one sentence, no build instructions.
[[nodiscard]] static std::string unavailableReason(ICoreWebFeature feature);
};
};
File-scope declarations#
// The application features a BROWSER cannot have -- the ⛔ rows of
// the web feature-support table -- and the one sentence a user is told
// when one is refused (web backend, WB8.3).
//
// The platform's own answer is ICoreCapabilities (ChildProcess, PseudoTerminal,
// ...); this is the APPLICATION's, one level up: which of its features that
enum class ICoreWebFeature {
Terminal, // F1
Git, // F2
UserCBlocks, // F3
UserPythonBlocks, // F4
CodeExportVerification, // F5
MatlabTargets, // F6
Copilot, // F7
Toolchains // F21
};