lang:
- add ag_loadContent(const QByteArray&) to Lang::Instance so fork code
can inject strings into the runtime lang system at any time
- ag_lang.h/cpp: embed Russian strings as compile-time literal, apply on
init and on every language switch via idChanges(); covers all ag_* keys
and lng_shortcuts_fast_message ("Быстрое сообщение {index}")
- res/lang/lang_arcanegram_ru.strings: human-readable Russian reference
fast-messages:
- replace fixed 10-slot UI with dynamic add/remove: starts at 1 slot,
"Add slot" grows the list up to 10, per-slot "Remove slot" shifts
entries down via RemoveSlot(index)
- store active count as Item<QString> CountStr with typed Count() /
SetCount() free functions; avoids Item<int> which has no
readPrefImpl/writePrefImpl specialisation (would cause LNK2019)
- slot rebuild driven by CountStr.changes() + InvokeQueued so widget
deletion is deferred past the click handler -- fixes _active.empty()
assertion in Ui::Animations::Manager::~Manager
- buttons use st::settingsButton so Rounded icon background fits the
left-padding and does not overlap the label
- settings_shortcuts.cpp Entries() loops over Count() instead of
hardcoding 10 rows -- keybind page shows only active slots
streamer:
- replace manual FlatLabel + extra divider/skip above preview label
with AddDividerText; removes duplicate spacing before sample name
9.9 KiB
| name | description |
|---|---|
| debugging-arcanegram-build | Use when a build error appears in this arcanegram repo, when link-time symbol mismatches surface, when chat rendering crashes at runtime, or when a hide / setting feature behaves incorrectly after restart. |
Debugging Arcanegram Build
A symptom → cause → fix catalog. Search this file by error text first before debugging from scratch — many failures are repeats from prior sessions.
When you encounter a new symptom and resolve it, append a new row to the relevant table before completing the task.
Compile errors
| Symptom (compiler text) | Cause | Fix |
|---|---|---|
'enumerateWindows': cannot access private member declared in class 'Core::Application' |
Core::Application::enumerateWindows is private |
Use Core::App().activeWindow()->widget()->update() (the public path). |
'start_with_next' is not a member of 'rpl' |
Wrong rpl pattern — this codebase doesn't expose start_with_next | producer | rpl::on_next([](auto v) { ... }, Lifetime()). Lifetime() is a static getter in your TU's anonymous namespace (mirror ag_forwarded_header.cpp). |
'lifetime' is not a member of 'Core::Application' |
No public lifetime() on App |
Same fix as above — define a static Lifetime() getter in your anonymous namespace, don't reach into App. |
_qs literal not declared / error C2065: '_qs' |
Wrong Qt string-literal suffix in this codebase | Use _q (e.g. u"foo"_q, not u"foo"_qs). |
'settingsDividerLabel' is not a member of 'st' |
Wrong style name | Use st::boxDividerLabel. |
'settingsDividerLabelPadding' is not a member of 'st' |
Wrong style name | Use st::defaultBoxDividerLabelPadding. |
'ag_xxx' is not a member of 'tr' after appending to lang_arcanegram.strings |
Worktree copy of the strings file is stale (file symlink fell back to plain copy on Windows without dev mode) | cp res/lang/lang_arcanegram.strings worktree/Telegram/Resources/langs/lang_arcanegram.strings then re-build. |
_addAction overload mismatch in Window::Filler::* (window_peer_menu.cpp) |
PeerMenuCallback::operator() requires (text, cb, const style::icon*) — three args, not two |
Pass nullptr as the icon argument. |
Ui::VerticalLayout::add: no matching overloaded function found |
Likely passing style::margins by name when the API wants a different type, or wrong overload |
Check wrap/vertical_layout.h — overloads are (object_ptr, style::align) and (object_ptr, const style::margins &, style::align). |
libyuv duplicate symbols (LNK2005, ~50 symbols like ScalePlane, CopyPlane) |
libavif and tg_owt both bundle libyuv with /Zi debug info |
See BUILD.md "Known issues" — -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT= (empty) in build-telegram.bat suppresses /Zi entirely, dodging the duplicate. misc/build-support.patch also strips libyuv from libavif structurally. |
'UserData::inputUser': non-standard syntax; use '&' to create a pointer to member (C3867) |
inputUser on UserData is a member function, not a field |
Call it: user->inputUser(), not user->inputUser. |
C2039 'X' is not a member of 'Arcanegram::Config::Sync' when the symbol lives in Arcanegram::Sync (sibling namespace) |
From inside namespace Arcanegram::Config, unqualified Sync:: resolves to the nested Config::Sync first, shadowing Arcanegram::Sync |
Fully qualify: ::Arcanegram::Sync::X. |
lambda declarator without a parameter list requires at least '/std:c++23preview' (C5279) |
C++23-only abbreviated lambda syntax: [] -> Type { ... } |
Write the parameter list explicitly: []() -> Type { ... }. |
LNK1181: cannot open input file '...\Release\<lib>.lib' (qt, openssl, tg_owt, libavif, etc.) often paired with LNK2038: mismatch detected for _ITERATOR_DEBUG_LEVEL '0' vs '2' and RuntimeLibrary 'MT_StaticRelease' vs 'MTd_StaticDebug' when running build-telegram.bat release |
prepare-deps.bat was last run with default debug (which passes skip-release to prepare.py) so Release halves of big libs were never built; CMake then tries to mix Release-config Telegram against Debug-only Qt plugin libs (/MTd, IDL=2) |
Run prepare-deps.bat both (~30 min); the skip-release toggle invalidates affected stages' cache keys so prepare.py rebuilds them with both configs. Then retry build-telegram.bat release. |
| C2027: использование неопределенного типа "Ui::SettingsButton" / C2039: 'setClickedCallback' is not a member of 'gsl::not_null<Settings::Button*>' when calling AddButtonWithIcon(...)->setClickedCallback(...) | settings_common.h only forward-declares Ui::SettingsButton; the full definition (and AbstractButton::setClickedCallback) lives in lib_ui | Add #include "ui/widgets/buttons.h" to the TU. |
| C2039: 'Id': is not a member of 'Lang' / C3861: 'Updated': identifier not found in fork code using ::Lang::Id() or ::Lang::Updated() | These free functions are declared in lang/lang_keys.h, not lang/lang_instance.h. Including only lang_instance.h leaves them undeclared. | Add #include "lang/lang_keys.h" alongside lang_instance.h. Also std::move the Updated() producer before piping into rpl::on_next. |
Runtime / behavior bugs
| Symptom | Cause | Fix |
|---|---|---|
| Hidden-users list resets to empty after every restart, even though saving worked in the same session | Hooks::init() ran before startLocalStorage(), so _prefs was empty when Load() read it from disk |
hooks__hooks-init patch must place Arcanegram::Hooks::init() after startLocalStorage() in Application::run (Telegram/SourceFiles/core/application.cpp ~line 271). |
| Hide-user works in scheduled / discussion / saved-messages threads but messages still show in regular chats | Patched HistoryView::ListWidget::refreshRows only — that class isn't used by HistoryInner (regular chat view) |
Override Element::isHidden() (consulted by Message::resizeContentGetHeight) and add early-returns in Message::draw and Message::resizeContentGetHeight for the user-hide case. |
| Hidden user's messages collapse but leave a margin-sized gap | Message::resizeContentGetHeight returns marginTop()+marginBottom() for isHidden() (which is what group-hide wants) |
Add an explicit user-hide branch returning 0 before the existing isHidden() margin branch. Also early-return at the top of Message::draw. |
| Reactions from hidden users still show on the bubble strip | InlineListDataFromMessage (history_view_reactions.cpp ~913) builds result.recent and result.reactions from raw item data |
Filter result.recent[id] by Arcanegram::HiddenUsers::IsHidden; subtract from matching result.reactions[i].count; drop reaction entirely if count drops to ≤ 0 (except paid). |
| Reactions still show in "who reacted" popup despite filtering on the strip | api/api_who_reacted.cpp resolves peers separately for the popup |
Add IsHidden check to the resolved-peers filter alongside the existing nullptr check (~line 443). |
STATUS_STACK_OVERFLOW on Telegram launch |
Historical link-order issue tied to libyuv duplicates being re-introduced after an upstream rebase | See BROKEN.md for the bisect notes. Check dumpbin /directives <lib> for embedded /DEFAULTLIB entries; verify misc/build-support.patch still strips libyuv from libavif. |
| Settings toggle persists in-memory but doesn't survive restart | Either the Hooks::init init-order issue (see above) — most common cause — or the _saveSettingsTimer hadn't been initialized yet when setValue was called |
Verify Hooks::init() is called after startLocalStorage(); setValue triggers Core::App().saveSettingsDelayed() which only fires once _saveSettingsTimer exists (created in Application::startLocalStorage). |
Assertion Failed! "forwarded->originalHiddenSenderInfo != nullptr" history_view_reply.cpp:590 when scrolling past a forwarded message that replies to a hidden user |
feature__hidden-users-reply-preview overrides Reply::sender() to return nullptr for hidden items, but Reply::senderName(view, data, shorten) then falls through to the forwarded branch and asserts originalHiddenSenderInfo on the resolved (replied-to) message — which can be a normal forward with originalSender set instead |
Add an early-return at the top of Reply::senderName(view, data, shorten): if data->resolvedMessage is from a hidden user, return tr::ag_hidden_user_name(tr::now) before walking the sender/forwarded branches. |
Stgit gotchas
| Symptom | Fix |
|---|---|
stg pop misc/branding.patch errors with invalid patch range |
Stgit uses underscore form internally — stg pop misc__branding. |
stg sink puts patch in unexpected slot |
Use stg sink --to=<target> to land immediately before the target in apply order. Always verify with stg series after. |
series file diverges from stgit internal order across sessions |
Internal stgit order is the source of truth; the series file in repo is just an export snapshot. Run pnpm run export to rewrite series to match current state. |
stg refresh captured the wrong patch |
Make sure the right patch is on top first (stg top to verify, stg float <name> to bring one up, then stg refresh). |
Adding a new patch and old patches show as modified after pnpm run export |
Whitespace / commit-hash drift from re-export. Don't stage them unless you actually changed the patch content — they'll re-export consistently next time. |
Build invocation
If build-telegram.bat fails with 'build-telegram.bat' is not recognized, you're running it through cmd //c from Git Bash — cwd inheritance breaks. Run it directly:
cd <repo root> && ./build-telegram.bat
Background execution is fine. Expect 30s–5min for incremental rebuilds, 30–45min for clean Debug.
When the symptom isn't here
Debug normally — read the actual error, locate the source line, identify the assumption that's broken, fix it. Then append a new row to this catalog so the next session benefits.